Next.js RAG with sources: cited answers in an App Router app
A chat box is easy in Next.js. A chat box whose answers a compliance officer will accept is not. The difference is provenance, and that is the part this SDK carries for you.
Last updated · SDK v1.1.0 · changelog
Short answer: install @uthereal-sdk/cortex, create app/api/cortex/route.ts with createCortexHandler, and call it from a client component with createCortexBrowserClient. Render answers with CitedAnswer so every claim shows its source. CORTEX_SHARED_API_KEY stays in server environment variables.
01
The route handler
// app/api/cortex/route.ts
import { createCortexHandler } from "@uthereal-sdk/cortex/server";
import { auth } from "@/lib/auth";
const handler = createCortexHandler({
config: {
baseUrl: process.env.CORTEX_API_BASE_URL!,
assistantId: process.env.CORTEX_ASSISTANT_ID!,
apiKey: process.env.CORTEX_SHARED_API_KEY!, // server only
},
allowedOrigin: process.env.NEXT_PUBLIC_SITE_URL!,
authenticate: async (request) => {
const session = await auth(request);
return session ? { id: session.user.id, externalUserId: session.user.id } : null;
},
store: yourStoreAdapter,
});
export const POST = handler;
export const GET = handler;Never import the server entry point from a client component. The key belongs to the route handler; the browser only ever talks to your own endpoint.
02
The client component
"use client";
import { createCortexBrowserClient } from "@uthereal-sdk/cortex/browser";
import { CitedAnswer } from "@uthereal-sdk/cortex/react";
const cortex = createCortexBrowserClient({ endpoint: "/api/cortex" });
export function Ask({ message }: { message: string }) {
// stream the answer, then render the saved message with citations
return <CitedAnswer answer={answer} messageId={id} loadPdf={cortex.pdf} />;
}03
Streaming and refusals
- Answers stream as NDJSON snapshots, so the first words appear immediately
- Each snapshot carries the claims and references resolved so far
- When no passage supports the question, the agent refuses instead of inventing
- Retrieval-only mode returns ranked JSON if you want to drive your own model
04
Production checklist
- API key in server environment variables, never NEXT_PUBLIC_
- Authenticate every request in the route handler before forwarding
- Scope conversation identifiers to the signed-in user, not to client input
- Set allowedOrigin to your deployed domain
- Clear client caches on sign-out so evidence is never shared between accounts
Frequently asked questions
- How do I add RAG to a Next.js app?
- Install @uthereal-sdk/cortex, expose one route handler at app/api/cortex/route.ts created with createCortexHandler, and call it from a client component with createCortexBrowserClient. The Cortex API key stays in server environment variables.
- Does it work with the App Router and Server Components?
- Yes. The handler is a standard Web Request and Response function, so it runs in a Route Handler on the Node.js or Edge runtime. The streaming client is a client component; Server Components can render everything around it.
- Can I deploy it to Vercel Edge or Cloudflare?
- Yes. The package is ESM with no Node-only native bindings, so the server entry runs on Node.js 22+, Vercel Edge, Cloudflare Workers, Deno 2 and Bun.
- How do citations render in React?
- The CitedAnswer component from @uthereal-sdk/cortex/react renders claim-level citations; PdfEvidence opens the cited page with the supporting passage highlighted.
- Do I need a vector database in Next.js?
- No. Retrieval, ranking and citation mapping happen in the hosted Cortex service, so there is no vector store, embedding job or reranker to run alongside your Next.js deployment.
Related
Ship a knowledge agent your users can trust
Create an agent, point the SDK at it, and let your AI coding tool do the wiring.
Questions? sdk@uthereal.ai