# Next.js RAG with sources: cited answers in an App Router app

> Add retrieval-augmented answers with real citations to a Next.js App Router app using @uthereal-sdk/cortex: a route handler on the server, a streaming client component, and PDF sources that open on the exact page.

- Canonical page: https://uthereal.ai/developers/nextjs-rag
- Last updated: 2026-09-18
- Product: Uthereal Cortex (sovereign enterprise AI, Swiss/EU data residency)
- npm package: `@uthereal-sdk/cortex` (https://www.npmjs.com/package/@uthereal-sdk/cortex)
- Repository: https://github.com/Uthereal-Labs/Uthereal-Cortex-SDK

## Short answer

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.

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.

## 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;
```
_app/api/cortex/route.ts_

> 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.

## 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} />;
}
```
_components/ask.tsx_

## 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

## 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 pages

- [SDK overview](https://uthereal.ai/developers/sdk): Full setup and API reference.
- [Cortex vs Vercel AI SDK](https://uthereal.ai/developers/vs-vercel-ai-sdk): Where each one fits.
- [PDF page citations](https://uthereal.ai/developers/pdf-citations): Highlighted source evidence.
- [npm package](https://uthereal.ai/developers/npm): Install, exports and runtimes.

## Next steps

- Create an agent and a scoped server key: https://agent.uthereal.ai
- Full SDK guide (HTML): https://uthereal.ai/developers/sdk
- Full SDK guide (Markdown): https://uthereal.ai/developers/sdk.md
- AI index for this site: https://uthereal.ai/llms.txt and https://uthereal.ai/llms-full.txt
- Help: sdk@uthereal.ai
