FeaturesEdit this page.md

HTTP context

With @lazarv/react-server you have access to everything related to the context of server-side rendering. This guide provides information for you how to access the HTTP context.

The following hooks / functions are available for you to access and manipulate the HTTP context.

All of these functions are available also in middlewares and route handlers with the file-system based router as these are runtime specific and not related to React.

With useHttpContext() you can get access to the full HTTP context.

import { useHttpContext } from "@lazarv/react-server"; export default function MyComponent() { const context = useHttpContext(); return ( <div> <p>Method: {context.request.method}</p> <p>URL: {context.request.url.toString()}</p> <p>Request Headers: {JSON.stringify(context.request.headers)}</p> <p>Request Cookies: {JSON.stringify(context.request.cookie)}</p> </div> ); };

With useRequest() you can get access to the full HTTP request.

import { useRequest } from "@lazarv/react-server"; export default function MyComponent() { const request = useRequest(); return ( <div> <p>Method: {request.method}</p> <p>URL: {request.url.toString()}</p> <p>Headers: {JSON.stringify(request.headers)}</p> <p>Cookies: {JSON.stringify(request.cookie)}</p> </div> ); };

With useResponse() you can get access to the full HTTP response. This is only available after the response has been sent to the client, in a React component which was suspended and streamed to the client later than the response was sent.

import { useResponse } from "@lazarv/react-server"; export default async function MyComponent() { const response = await useResponse(); return ( <div> <p>Headers: {JSON.stringify(response.headers)}</p> <p>Cookies: {JSON.stringify(response.cookie)}</p> </div> ); };

With useUrl() you can get access to the URL of the current request.

import { useUrl } from "@lazarv/react-server"; export default function MyComponent() { const url = useUrl(); return <p>URL: {url.href}</p>; };

With usePathname() you can get access to the pathname of the current request.

import { usePathname } from "@lazarv/react-server"; export default function MyComponent() { const pathname = usePathname(); return <p>Pathname: {pathname}</p>; };

With useSearchParams() you can get access to the search params of the current request. This is an object with key-value pairs of the search params. In case of multiple values for the same key, the value will be an array.

import { useSearchParams } from "@lazarv/react-server"; export default function MyComponent() { const searchParams = useSearchParams(); return ( <p>Search params: {JSON.stringify(searchParams)}</p> ); };

With headers() you can get access to the headers of the current request.

import { headers } from "@lazarv/react-server"; export default function MyComponent() { const requestHeaders = headers(); return <p>Headers: {JSON.stringify(requestHeaders)}</p>; };

You can also modify the headers of the current response by passing an object of key-value pairs:

import { headers } from "@lazarv/react-server"; export default function MyComponent() { headers({ "X-My-Header": "My value", }); return <p>Headers: {JSON.stringify(headers())}</p>; };

Or by passing a Headers object:

import { headers } from "@lazarv/react-server"; export default function MyComponent() { headers(new Headers({ "X-My-Header": "My value", })); return <p>Headers: {JSON.stringify(headers())}</p>; };

Or by passing an array of key-value pairs:

import { headers } from "@lazarv/react-server"; export default function MyComponent() { headers([ ["X-My-Header", "My value"], ]); return <p>Headers: {JSON.stringify(headers())}</p>; };

Modifying the headers with the headers() function will override the headers of the current response. If you want to mutate the response headers directly, you can use three addition helper functions to set, append or delete headers. These functions are setHeader(), appendHeader() and deleteHeader().

import { setHeader, appendHeader, deleteHeader } from "@lazarv/react-server"; export default function MyComponent() { setHeader("X-My-Header", "My first value"); appendHeader("X-My-Header", "My second value"); deleteHeader("X-My-Header"); return <p>Check the response headers!</p>; }

Note: Keep in mind that HTTP headers are case-insensitive!

With cookie() you can get access to the cookies of the current request.

import { cookie } from "@lazarv/react-server"; export default function MyComponent() { const requestCookies = cookie(); return <p>Cookies: {JSON.stringify(requestCookies)}</p>; };

You can also set or delete cookies in the context of the current response.

import { setCookie, deleteCookie } from "@lazarv/react-server"; export default function MyComponent() { setCookie("my-cookie", "my-value"); deleteCookie("other-cookie"); return <p>Cookies: {JSON.stringify(cookie())}</p>; };

With status() you can set the status code and text of the current response.

import { status } from "@lazarv/react-server"; export default function MyComponent() { status(404, "Not found"); return <p>Not Found</p>; };

With useFormData() you can get access to the form data of the current request.

import { useFormData } from "@lazarv/react-server"; export default function MyComponent() { const formData = useFormData(); return ( <p>Form data: {JSON.stringify(Object.fromEntries(formData.entries()))}</p> ); };

With redirect() you can redirect the current request to another URL.

Warning: the redirect() function will throw an error which will be caught by the runtime and will result in a redirect. When you want to use redirect() in a try/catch block, make sure you rethrow the error if it's a redirect error.

import { redirect } from "@lazarv/react-server"; export default function MyComponent() { redirect("https://example.com"); };

The redirect() function accepts an optional third argument kind that controls how the redirect is performed on the client. The available kinds are:

KindDescription
"navigate"(default) Performs an RSC navigation using replaceState. The browser URL changes without adding a history entry.
"push"Performs an RSC navigation using pushState. The browser URL changes and a new history entry is added, so the user can navigate back.
"location"Forces a full browser navigation via location.href. Useful for redirecting to external URLs or when a full page reload is needed.
"error"Throws the redirect error on the client instead of navigating. This allows custom handling via try/catch in server action calls.
import { redirect } from "@lazarv/react-server"; // RSC navigation with pushState (adds history entry) redirect("/dashboard", 302, "push"); // Full browser navigation redirect("/oauth/authorize", 302, "location"); // Throw on client for custom handling redirect("/login", 302, "error");

When using the "error" kind in a server action, the client can catch the redirect error and handle it:

"use client"; import { myServerAction } from "./actions"; export function MyComponent() { const handleClick = async () => { try { await myServerAction(); } catch (e) { if (e?.digest?.startsWith("Location=")) { const url = e.digest.split("Location=")[1]?.split(";")[0]; console.log(`Redirect to: ${url}`); } } }; return <button onClick={handleClick}>Submit</button>; }

With rewrite() you can rewrite the current request to another URL. This is useful to modify the URL pathname of the current request in a middleware function.

import { rewrite, useUrl } from "@lazarv/react-server"; export function init$() { return async () => { const { pathname } = useUrl(); if (pathname === "/old-pathname") { rewrite("/new-pathname"); } }; } export default function MyComponent() { const { pathname } = useUrl(); return <p>Current pathname: {pathname}</p>; }

With useOutlet() you can get access to the outlet of the current request. This is useful to get the name of the outlet where the current request is rendered.

import { useOutlet } from "@lazarv/react-server"; export default function MyComponent() { const outlet = useOutlet(); return <p>Outlet: {outlet}</p>; }

With useRender() you can get access to the render lock of the current request. This is useful if you want to lock rendering of a React Server Component while the async function is running or until the lock is released, as React Server Components are rendered using streaming by default. This is especially useful for handling HTTP headers and cookies in an async React Server Component. Without locking the rendering, the headers and cookies will be sent to the client before the async function is finished. When a lock is detected in the rendering process, the rendering will wait for the lock to be released before beginning to send the headers and cookies to the client and starting the streaming of the React Server Component.

import { headers, useRender } from "@lazarv/react-server"; export default function MyComponent() { const { lock } = useRender(); await lock(async () => { // Do something async await new Promise((resolve) => setTimeout(resolve, 1000)); headers({ "x-lock": "works", }); }); return <p>Render lock</p>; }

You can also use the lock() function to get an unlock() function to release the lock later.

import { headers, useRender } from "@lazarv/react-server"; export default function MyComponent() { const { lock } = useRender(); const unlock = lock(); // Do something async await new Promise((resolve) => setTimeout(resolve, 1000)); headers({ "x-lock": "works", }); unlock(); return <p>Render lock</p>; }

With logger you can log messages using the runtime's built-in logger. The logger object provides info, warn, error, and debug methods that integrate with the runtime's logging system, providing consistent and formatted output.

import { logger } from "@lazarv/react-server"; export default function MyComponent() { logger.info("Rendering MyComponent"); return <p>Hello World</p>; }

The logger automatically uses the runtime's Vite-integrated logger in development mode for nicely formatted output, and falls back to console in production. It is context-aware — when called inside an after() callback, the log output is annotated with an (after) label so you can distinguish post-response logs from rendering logs.

import { after, logger } from "@lazarv/react-server"; export default function MyComponent() { logger.info("Rendering component"); after(() => { logger.info("Response sent"); // logged with (after) label in dev }); return <p>Hello World</p>; }

The available methods are:

MethodDescription
logger.info(msg, ...args)Log an informational message
logger.warn(msg, ...args)Log a warning message
logger.error(msg, ...args)Log an error message or Error object
logger.debug(msg, ...args)Log a debug message

Note: The logger can be used anywhere on the server — in components, server functions, middleware, route handlers, workers, and after() callbacks. It does not require a request context, but when one is available, it uses the context-specific logger instance.

With after() you can register a callback function that runs after the response has been sent to the client. This is useful for performing cleanup tasks, logging, analytics, or any side effects that should not delay the response.

import { after, logger } from "@lazarv/react-server"; export default function MyComponent() { after(() => { logger.info("Response sent to client."); }); return <p>Hello World</p>; }

The after() hook can be called multiple times to register multiple callbacks. All registered callbacks run concurrently via Promise.allSettled after the response stream completes, so one failing callback does not prevent the others from running.

import { after } from "@lazarv/react-server"; export default function MyComponent() { after(async () => { await saveAnalytics({ page: "/home", timestamp: Date.now() }); }); after(async () => { await cleanupTempFiles(); }); return <p>Home</p>; }

You can also use after() in server functions, middleware, route handlers, or any server-side code that runs within a request context:

import { after } from "@lazarv/react-server"; export async function submitForm(formData) { "use server"; const data = Object.fromEntries(formData.entries()); await saveToDatabase(data); after(async () => { await sendNotificationEmail(data.email); }); }

Note: The after() hook can only be called during a request. Calling it outside of a request context (e.g., at module scope or in a standalone script) will throw an error.