Context Serialization
Context Serialization
Context serialization allows server-side context values to be transferred to the client during hydration. This enables the client to access data that was set by server middleware without making additional requests.
When to Use Context Serialization
- Sharing user session data across server and client
- Passing configuration set during SSR to the client
- Hydrating client-side state managers (e.g., TanStack Query)
- Avoiding duplicate data fetching on initial page load
Server Session Data
This data was set by server middleware and serialized to the client:
- Session ID
- f1f4c3e2
- Server Timestamp
- 2026-03-09T09:04:43.673Z
- Server PID
- 318
How It Works
1. Create and register context (context/server-session.ts)
import { createContext } from "react-router";
import { registerContext } from "@udibo/juniper";
export interface ServerSession {
sessionId: string;
serverTimestamp: string;
serverPid: number;
}
export const serverSessionContext = createContext<ServerSession>();
export function createServerSession(): ServerSession {
return {
sessionId: crypto.randomUUID().slice(0, 8),
serverTimestamp: new Date().toISOString(),
serverPid: Deno.pid,
};
}
// Register serialization for this context
registerContext<ServerSession>({
name: "serverSession",
context: serverSessionContext,
serialize: (session) => session,
deserialize: (data) => data as ServerSession,
});2. Set context in server middleware (routes/main.ts)
import { Hono } from "hono";
import type { AppEnv } from "@udibo/juniper/server";
import {
createServerSession,
serverSessionContext,
} from "@/context/server-session.ts";
const app = new Hono<AppEnv>();
// Set server session in context for all routes
app.use(async (c, next) => {
const context = c.get("context");
context.set(serverSessionContext, createServerSession());
await next();
});
export default app;3. Access context in loaders (routes/my-route.tsx)
import type { AnyParams, RouteLoaderArgs, RouteProps } from "@udibo/juniper";
import { serverSessionContext } from "@/context/server-session.ts";
import type { ServerSession } from "@/context/server-session.ts";
// Loaders run on both server (SSR) and client (navigation)
export function loader({ context }: RouteLoaderArgs) {
return context.get(serverSessionContext);
}
export default function MyRoute({ loaderData }: RouteProps<AnyParams, ServerSession>) {
return <p>Session ID: {loaderData.sessionId}</p>;
}4. Browser-only code in loaders (optional)
import type { RouteLoaderArgs } from "@udibo/juniper";
import { isBrowser } from "@udibo/juniper/utils/env";
export function loader({ context }: RouteLoaderArgs) {
const data = context.get(myContext);
// Use isBrowser() for browser-only APIs
if (isBrowser()) {
// This only runs on client-side navigation, not during SSR
localStorage.setItem("lastVisited", new Date().toISOString());
}
return data;
}Note: The server session data shown above was set during SSR and transferred to the client via context serialization. The client can access this data immediately without making any additional requests.