Open Kortyx on GitHub

React Frontend + Node Backend

Updated 6 hours ago • May 22, 2026

Use this shape when the UI and backend are deployed separately, or when backend ownership should stay independent from the React app.

The architecture rule is simple: the Node backend owns Kortyx execution. The React frontend consumes the stream protocol.

Backend Responsibilities

  • Own createAgent(...), workflows, nodes, providers, auth, rate limits, and runtime persistence.
  • Expose a chat route that accepts messages, sessionId, workflowId, and approved context.
  • Return SSE for live streaming.
  • Return buffered JSON only for non-live clients or tests.

Frontend Responsibilities

  • Use @kortyx/react for chat state and transport.
  • Render finalized messages separately from active streamContentPieces.
  • Send only request metadata as client context.
  • Never send provider credentials or server-only config to the browser.

Backend Route Shape

For a Fetch-compatible Node route, the handler can stay close to the Next.js API route shape.

import { collectBufferedStream, parseChatRequestBody, toSSE } from "kortyx"; import { agent } from "../lib/kortyx-client"; import { requireUser } from "../services/auth"; export async function handleChatRequest(request: Request): Promise<Response> { const user = await requireUser(request); const body = parseChatRequestBody(await request.json()); const stream = await agent.streamChat(body.messages, { sessionId: body.sessionId, workflowId: body.workflowId, context: { ...body.context, userId: user.id, tenantId: user.tenantId, }, }); if (body.stream === false) { return Response.json(await collectBufferedStream(stream)); } return toSSE(stream); }

Express, Fastify, Hono, and similar frameworks can adapt the same handler shape. Keep the same request body semantics and return the same SSE stream protocol.

Good to know: Always authenticate and rate-limit before calling agent.streamChat(...). Treat client context as request metadata only; derive user id, roles, tenant access, and billing access on the backend.

React Transport

On the frontend, point createRouteChatTransport(...) at the backend URL.

import { createRouteChatTransport, useChat } from "@kortyx/react"; export function ChatPage({ apiBaseUrl }: { apiBaseUrl: string }) { const chat = useChat({ transport: createRouteChatTransport({ endpoint: `${apiBaseUrl}/chat`, }), context: { source: "web", }, }); return <ChatWindow chat={chat} />; }

Custom Backends

Use a custom transport only when your backend cannot expose the standard Kortyx stream protocol. A custom transport must:

  • preserve sessionId, workflowId, messages, and context semantics
  • call onChunk for every parsed stream chunk
  • forward context.signal to fetch or the request layer so abort() works
  • surface transport errors instead of swallowing them

See React Client for the full transport shape.