Skip to content

Next.js AI prompt

Rules that make your coding agent build AI features in Next.js 16 the current way: useChat with message parts, a streaming Route Handler, typed tools with approvals, and chats that save.

What it makes your agent good at

Agents trained on older tutorials still write useChat with input and handleSubmit, return StreamingTextResponse, read message.content and leave a key one NEXT_PUBLIC_ away from the browser. This prompt gives them the AI SDK as it ships today, versions 6 and 7 side by side, plus the parts tutorials skip: auth and rate limits on the route, approvals for risky tools, saved chats with server ids, and a UI built on your own chat components.

  1. Today's AI SDK, 6 or 7Reads the installed version and writes its names: instructions or system, isStepCount or stepCountIs, toolApproval or needsApproval, never a mix.
  2. Messages rendered by partsuseChat with sendMessage, status, stop and regenerate; text, reasoning, tool, source and file parts mapped onto your chat components.
  3. A chat route that's safe to shipSession check, per-user rate limit, validated messages, server-side instructions, a model allowlist, maxDuration and safe error messages.
  4. Tools with a human in the loopTyped tools built per user, step limits so replies finish, and approvals answered with addToolApprovalResponse and signed against forgery.
  5. Chats that save and reloadServer message ids, persistence when the stream ends, last-message requests with ownership checks, and a deliberate choice about closed tabs.
  6. Streaming without jankThrottled renders, stable keys, memoized Markdown, smoothStream for bursty providers, and scrolling that respects the reader.

The Next.js AI rules

120 lines, current to Next.js 16.4, React 19.3 and AI SDK 7 or 6. Last reviewed October 23, 2026. Plain Markdown, no front matter: each agent's is below.

Download

nextjs-ai.md

# Next.js AI

You are working in a Next.js 16 App Router project with React 19, TypeScript and the AI SDK (`ai`, `@ai-sdk/react`, and the AI Gateway or a provider package). Write code for the versions in `package.json`, not the ones in your training data: the AI SDK replaced its chat API in version 5 and renamed much of it again in version 7.

## Before you write code

- Read the `ai` version in `package.json`. AI SDK 7 is current and 6 is still common. Version 7 keeps most version 6 names as deprecated aliases, so both compile: write the installed major's names and never mix them.

| AI SDK 6 | AI SDK 7 |
| --- | --- |
| `system` on `streamText` and `generateText` | `instructions` |
| `stepCountIs(n)` | `isStepCount(n)` |
| `onFinish`, `onStepFinish` on the server | `onEnd`, `onStepEnd` |
| `result.toUIMessageStreamResponse(options)` | `createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream, ...options }) })` |
| `needsApproval` on a tool | `toolApproval: { toolName: "user-approval" }` on the call |
| `experimental_throttle` on `useChat` | `throttle` |
| `totalUsage` for all steps (`usage` is the last step) | `usage` |

- The package ships its docs: read `node_modules/ai/docs/` (`02-getting-started/02-nextjs-app-router.mdx`, `04-ai-sdk-ui/`, `08-migration-guides/`) before using an API you are not sure of.
- Look for the project's chat components (`components/ui/`, `components/ai-elements/`): Message, PromptInput, Reasoning, Tool, Sources, Confirmation. Build on them instead of writing new bubbles, inputs or spinners.
- Find the project's auth helper, where model ids live, and whether it uses the AI Gateway (`AI_GATEWAY_API_KEY`, `"provider/model"` strings) or provider packages (`@ai-sdk/anthropic`, `@ai-sdk/openai`). Never invent a model id: reuse the project's or ask.

## The chat route

Stream chats from a Route Handler that converts UI messages, streams, and returns a UI message stream:

```ts
// app/api/chat/route.ts, AI SDK 7
import {
  convertToModelMessages,
  createUIMessageStreamResponse,
  isStepCount,
  streamText,
  toUIMessageStream,
  type UIMessage,
} from "ai";

export const maxDuration = 60;

export async function POST(req: Request) {
  const session = await getSession();
  if (!session) return new Response("Unauthorized", { status: 401 });
  const { messages }: { messages: UIMessage[] } = await req.json();

  const result = streamText({
    model: chatModel,
    instructions: INSTRUCTIONS,
    messages: await convertToModelMessages(messages),
    tools: createTools(session.user.id),
    stopWhen: isStepCount(5),
    abortSignal: req.signal,
  });

  return createUIMessageStreamResponse({
    stream: toUIMessageStream({ stream: result.stream, sendSources: true }),
  });
}
```

On AI SDK 6 the route uses `system`, `stepCountIs(5)` and `return result.toUIMessageStreamResponse({ sendSources: true })`.

- `convertToModelMessages` is async: `await` it.
- Check the session before reading the body, and rate-limit per user (a sliding window in Redis or the database) before calling the model. Answer 401 and 429 as plain responses.
- The body is untrusted. Drop `system` messages from the client, cap the number and size of messages, and `await validateUIMessages({ messages, tools })` when they carry tool or data parts. Instructions, model and user id come from the server, never from the request.
- Export `maxDuration` sized to the longest run you allow, and no `runtime` export: the Edge runtime is deprecated in Next.js 16.
- Bound the cost of a request: set `maxOutputTokens`, trim long histories before converting them, and record each user's usage in `streamText`'s `onEnd` (`onFinish` on 6).
- Without `stopWhen`, `streamText` stops after one step, so a tool call ends the reply with no answer. Set a step limit whenever there are tools.
- The client sees "An error occurred." by default. Pass `onError` to the UI message stream to map known errors to safe messages, and log the real error on the server.
- `sendReasoning` defaults to true and `sendSources` to false: set both to what the UI shows.
- Use a Route Handler for chat; use a Server Function for one-shot generation a form waits for. Never fetch your own `/api/chat` from a Server Component.

## Models and keys

- Provider keys and `AI_GATEWAY_API_KEY` live in server env without the `NEXT_PUBLIC_` prefix. Only Route Handlers and Server Functions call models; modules that build models or tools start with `import "server-only"`.
- Through the Gateway a model is a `"provider/model"` string; otherwise a provider instance such as `anthropic("model-id")`. Keep the choice in one module so switching providers changes one line.
- When users pick a model, the client sends a key from the list you offer and the server maps it through an allowlist record. Provider-specific settings go in `providerOptions`, keyed by provider.

## The chat UI

- The chat is a Client Component using `useChat` from `@ai-sdk/react`. Keep the input in your own state and call `sendMessage({ text, files })`; send per-request values with `sendMessage(message, { body })`, and point at another route with `transport: new DefaultChatTransport({ api })` from `ai`.
- `status` is `"submitted"`, `"streaming"`, `"ready"` or `"error"`. While submitted or streaming, the send button becomes a stop button calling `stop()`. On error, show a generic message and a retry calling `regenerate()`; `regenerate({ messageId })` reruns one reply.
- Render `message.parts` in order, switching on `part.type`: `text`, `reasoning`, `file`, `source-url`, `source-document`, `tool-<name>`, `dynamic-tool`, `data-<name>`. There is no `message.content`.
- A tool part's `state` is `input-streaming`, `input-available`, `approval-requested`, `approval-responded`, `output-available` (`preliminary: true` while it still streams), `output-error` or `output-denied`. Handle each one.
- Type the hook: `useChat<ChatMessage>()` with `UIMessage<Metadata, DataParts, InferUITools<ReturnType<typeof createTools>>>`, imported with `import type` so server code stays out of the client bundle.
- Map parts onto the project's components: Message per turn, Reasoning, Tool, Sources, Confirmation for approvals, PromptInput as the composer with its stop state.
- Stream without jank: throttle renders (`throttle: 50` on 7, `experimental_throttle: 50` on 6), key messages by `message.id`, memoize the Markdown renderer per part, and auto-scroll only while the reader is at the bottom. For bursty providers, add `experimental_transform: smoothStream()` to `streamText`.
- Send usage or the model per message with `messageMetadata` on the UI message stream and read `message.metadata`.

## Tools and approvals

- Define tools with `tool({ description, inputSchema, execute })` and a Zod schema whose fields use `.describe()`. Return small JSON. A thrown error becomes an `output-error` part the model reads, so throw messages it can act on.
- Build tools per request in a factory that closes over the signed-in user (`createTools(userId)`) and authorize inside `execute`. Never take a user or tenant id from tool input.
- Require approval for side effects: `needsApproval: true` (or a function of the input) on the tool on 6, `toolApproval: { deleteFile: "user-approval" }` on `streamText` on 7. Answer the `approval-requested` part with `addToolApprovalResponse({ id: part.approval.id, approved })` and pass `sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses` to `useChat` so the reply continues. Set `experimental_toolApprovalSecret` so an approval forged in the client's history is rejected.
- Client-side tools have no `execute`: handle them in `onToolCall` (check `toolCall.dynamic` first), call `addToolOutput` without awaiting it, and pass `sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls`.

## Structured output

- Use `generateText({ output: Output.object({ schema }) })` and read `result.output`; `streamText` with `output` gives `partialOutputStream`. `Output.array({ element })` and `Output.choice({ options })` cover lists and labels. `generateObject` and `streamObject` are deprecated.
- With tools, the output is one more step: leave room in `stopWhen`. Catch `NoObjectGeneratedError` (schema mismatch) and `NoOutputGeneratedError` (the run ended on a tool call) and offer a retry.

## Saving chats

- Create the chat on the server and route to `/chat/[id]`; the page loads its messages and passes `id` and `messages` to `useChat`. Store `UIMessage[]` with their parts, not model messages.
- Give replies server ids with `originalMessages: messages` and `generateMessageId: createIdGenerator({ prefix: "msg", size: 16 })` on the UI message stream, then save the `messages` passed to `onEnd` (`onFinish` on 6).
- Send only the last message with the transport's `prepareSendMessagesRequest`; the route loads the history, checks the chat belongs to the user, and validates it.
- Decide what a closed tab means. To finish and save anyway, do not forward `req.signal`, and call `result.consumeStream()` without awaiting it. To stop paying when the reader stops, forward `req.signal` as above, pass `consumeSseStream: consumeStream` to the response, and save the partial reply when `isAborted` is true.

## Do not

- Do not write AI SDK 4 chat code: `input`, `handleInputChange`, `handleSubmit`, `isLoading`, `append`, `reload`, `message.content`, `maxSteps`, or tool `parameters` (now `inputSchema`).
- Do not return `StreamingTextResponse`, `toDataStreamResponse()` or `OpenAIStream`, even where older docs show them.
- Do not start new features on `@ai-sdk/rsc` (`streamUI`, `createStreamableValue`): it is experimental, and AI SDK UI is the supported path.
- Do not call a provider from the browser, expose a key with `NEXT_PUBLIC_`, or let the client set the instructions, the raw model id or the user id.

## Before you finish

- Run the type checker and the linter, and fix what they report.
- In the browser: send, stop mid-reply, regenerate, approve and deny a tool, reload a saved chat, and break the key to see the safe error.
- Test tools by calling `execute` directly (mock `server-only` in the test setup), and routes with a mock model from `ai/test` (`MockLanguageModelV3` on 6, `MockLanguageModelV4` on 7), copying its response shape from `node_modules/ai/docs/03-ai-sdk-core/55-testing.mdx`.
- Say which model, `maxDuration`, step limit and rate limit you chose.

10,432 characters, 1,489 words. Under Windsurf's 12,000-character limit for a rule, as every prompt here is.

Use it in your agent

The same rules, where your agent reads them. Each file has the front matter its agent needs, set to load when the task fits.

Claude Code

A rule it loads every session

  1. Save it as .claude/rules/nextjs-ai.md in your project, front matter included, or run the install command.
  2. Claude Code loads every file in .claude/rules with your CLAUDE.md when a session starts.
  3. Prefer one file? Paste it into CLAUDE.md under its own heading instead.

.claude/rules/nextjs-ai.md

# Next.js AIYou are working in a Next.js 16 App Router project with React 19, TypeScript and the AI SDK (`ai`, `@ai-sdk/react`, and the AI Gateway or a provider package). Write code for the versions in `package.json`, not the ones in your training data: the AI SDK replaced its chat API in version 5 and renamed much of it again in version 7.## Before you write code- Read the `ai` version in `package.json`. AI SDK 7 is current and 6 is still common. Version 7 keeps most version 6 names as deprecated aliases, so both compile: write the installed major's names and never mix them.| AI SDK 6 | AI SDK 7 || --- | --- || `system` on `streamText` and `generateText` | `instructions` || `stepCountIs(n)` | `isStepCount(n)` |…

Or let the shadcn CLI write this file: sign in (free) for your command.

Cursor

A project rule with front matter

  1. Save it as .cursor/rules/nextjs-ai.mdc, front matter included, or run the install command.
  2. Cursor attaches it when you work on matching files, or when the task fits its description.
  3. Check it under Cursor Settings, Rules, then commit the folder for your team.

.cursor/rules/nextjs-ai.mdc

---description: "Building AI features in Next.js with the AI SDK: chat Route Handlers, useChat UIs, tools and approvals, structured output and saved chats."alwaysApply: false---# Next.js AIYou are working in a Next.js 16 App Router project with React 19, TypeScript and the AI SDK (`ai`, `@ai-sdk/react`, and the AI Gateway or a provider package). Write code for the versions in `package.json`, not the ones in your training data: the AI SDK replaced its chat API in version 5 and renamed much of it again in version 7.## Before you write code- Read the `ai` version in `package.json`. AI SDK 7 is current and 6 is still common. Version 7 keeps most version 6 names as deprecated aliases, so both compile: write the installed major's names and never mix them.| AI SDK 6 | AI SDK 7 || --- | --- || `system` on `streamText` and `generateText` | `instructions` || `stepCountIs(n)` | `isStepCount(n)` |…

Or let the shadcn CLI write this file: sign in (free) for your command.

Windsurf

A workspace rule for Cascade

  1. Save it as .windsurf/rules/nextjs-ai.md, or run the install command.
  2. trigger: model_decision lets Cascade pull it in when the task fits its description.
  3. Windsurf reads up to 12,000 characters per rule; this one is 10,432.

.windsurf/rules/nextjs-ai.md

---trigger: model_decisiondescription: "Building AI features in Next.js with the AI SDK: chat Route Handlers, useChat UIs, tools and approvals, structured output and saved chats."---# Next.js AIYou are working in a Next.js 16 App Router project with React 19, TypeScript and the AI SDK (`ai`, `@ai-sdk/react`, and the AI Gateway or a provider package). Write code for the versions in `package.json`, not the ones in your training data: the AI SDK replaced its chat API in version 5 and renamed much of it again in version 7.## Before you write code- Read the `ai` version in `package.json`. AI SDK 7 is current and 6 is still common. Version 7 keeps most version 6 names as deprecated aliases, so both compile: write the installed major's names and never mix them.| AI SDK 6 | AI SDK 7 || --- | --- || `system` on `streamText` and `generateText` | `instructions` || `stepCountIs(n)` | `isStepCount(n)` |…

Or let the shadcn CLI write this file: sign in (free) for your command.

GitHub Copilot

Instructions for the repository

  1. Save it as .github/instructions/nextjs-ai.instructions.md, or run the install command.
  2. applyTo: "**" applies it to every request in this repository.
  3. Or paste it into .github/copilot-instructions.md, which Copilot reads for every request.

.github/instructions/nextjs-ai.instructions.md

---description: "Building AI features in Next.js with the AI SDK: chat Route Handlers, useChat UIs, tools and approvals, structured output and saved chats."applyTo: "**"---# Next.js AIYou are working in a Next.js 16 App Router project with React 19, TypeScript and the AI SDK (`ai`, `@ai-sdk/react`, and the AI Gateway or a provider package). Write code for the versions in `package.json`, not the ones in your training data: the AI SDK replaced its chat API in version 5 and renamed much of it again in version 7.## Before you write code- Read the `ai` version in `package.json`. AI SDK 7 is current and 6 is still common. Version 7 keeps most version 6 names as deprecated aliases, so both compile: write the installed major's names and never mix them.| AI SDK 6 | AI SDK 7 || --- | --- || `system` on `streamText` and `generateText` | `instructions` || `stepCountIs(n)` | `isStepCount(n)` |…

Or let the shadcn CLI write this file: sign in (free) for your command.

Codex & AGENTS.md

The file most agents read

  1. Paste it into AGENTS.md at your project's root, under its own heading.
  2. Codex reads AGENTS.md before it starts work, and so do Cursor, Zed, Jules, Amp and Copilot's coding agent.
  3. A folder can have its own AGENTS.md: the one closest to the file being edited wins.

AGENTS.md

## Next.js AIYou are working in a Next.js 16 App Router project with React 19, TypeScript and the AI SDK (`ai`, `@ai-sdk/react`, and the AI Gateway or a provider package). Write code for the versions in `package.json`, not the ones in your training data: the AI SDK replaced its chat API in version 5 and renamed much of it again in version 7.### Before you write code- Read the `ai` version in `package.json`. AI SDK 7 is current and 6 is still common. Version 7 keeps most version 6 names as deprecated aliases, so both compile: write the installed major's names and never mix them.| AI SDK 6 | AI SDK 7 || --- | --- || `system` on `streamText` and `generateText` | `instructions` || `stepCountIs(n)` | `isStepCount(n)` |…

AGENTS.md is shared with your own instructions, so paste the rules in: the copy sets their headings a level down.

Rules teach it. The MCP equips it. With Pro, your agent installs every component, block and icon it needs, from a prompt.

Get Pro

Pricing

Give your agent the parts, with Pro

The prompts are free. Every Pro plan adds the MCP server, so your agent installs the components, blocks and icons it writes code around.

4.9/5 out of 5 · 150+ reviewsfrom 150+ founders and developers.

Billed once a year in USD. Cancel anytime.

Individual

For personal projects & open source

$32instead of $49/mo

$389 billed yearly

  • How many people can use the license.Seats: 1 seat
  • Client work, SaaS products and anything you charge for.Commercial use: Personal & open source only
  • Page sections in 56 categories, from heroes and pricing tables to dashboards and settings, on every framework and UI library, in your theme.Blocks: All 6,181 blocks
  • Complete Next.js sites for startups, SaaS, agencies and portfolios, every page designed, ready to ship.Templates: All 14 templates
  • Your AI agent searches, previews and installs any component, block, icon or DESIGN.md from a prompt: 22 tools in Claude Code, Cursor, VS Code and 35 more clients.MCP server: 38 AI clients
  • Buttons with motion and states of their own, from an arrow that slides in to a burst of confetti.Animated buttons: All 35 buttons
  • Typewriters, scrambles, counters and more, for headlines, labels and numbers.Text effects: All 97 effects
  • Animated backgrounds for heroes, sections and cards, from a soft aurora to a flock that flees the cursor. Most are pure CSS.Backgrounds: All 100 backgrounds
  • WebGPU shaders, from a slow aurora to a black hole, each drawing only while it's on screen.Shaders: All 100 shaders
  • One design and one theme on all four: the components, blocks and effects are built for each framework.Frameworks: React, Vue, Svelte, Solid
  • React on Base UI, Radix UI, React Aria or Ark UI: install the version for the library your project already uses. Vue, Svelte and Solid run on Ark UI.UI libraries: Base UI, Radix, Aria, Ark
  • From a button to a date picker, a color picker or a guided tour: accessible, typed in TypeScript, each with live demos.Components: All 174 components
  • Real-world patterns built from the components, in 53 galleries: forms, tables, menus, dialogs and more.Examples: All 1,103 examples
  • Area, bar, line, pie, radar and radial charts on TanStack Charts, on every framework. React also gets the Recharts originals.Charts: All 70 charts
  • Debounce, local storage, media queries and more: each hook is one typed file you own.React hooks: All 35 hooks
  • From 222 libraries, Lucide, Heroicons, Tabler and Material Symbols among them, as SVG or a React component in one command.Icons: 294k+ icons
  • Stripe, Linear, Apple and 497 more: a brand's colors, typography and components in one file your AI agent builds from.DESIGN.md files: All 500 brands
  • Restyle every component and block at once: 8 styles, 7 grays, 18 colors and 5 radii, shared as a shadcn preset code.Theme builder: 8 styles × 18 colors
  • Priority requests are answered first.Support: Standard

Team

Most popular

For freelancers, agencies & startups

$66instead of $99/mo

$789 billed yearly · ≈ $13/dev/mo

Everything in Individual, plus

  • How many people can use the license.Seats: Up to 5 seats
  • Client work, SaaS products and anything you charge for.Commercial use: Included
  • Priority requests are answered first.Support: Priority

Organization

For companies with larger teams

$132instead of $199/mo

$1,589 billed yearly

Everything in Team, plus

  • How many people can use the license.Seats: Unlimited seats
  • Secure checkout via Stripe
  • Code lives in your repo
  • Keep what you've shipped if you cancel
  • License terms

Next.js AI prompt FAQ

What the Next.js AI prompt covers and how to use it in your agent.

Is the Next.js AI prompt written for AI SDK 6 or AI SDK 7?

Both. It has the agent read the installed version first and gives it a table of the names that changed in 7, such as instructions for system, isStepCount for stepCountIs and toolApproval for needsApproval. Version 7 still accepts most version 6 names as deprecated aliases, so the rule is to write one major's names and never mix them.

Why does the Next.js AI prompt forbid input and handleSubmit in useChat?

They belong to AI SDK 4. Since version 5, useChat leaves the input state to you and sends with sendMessage, and each message carries an ordered parts array instead of content. The prompt lists the removed names under Do not, so the agent stops reaching for them.

Does the Next.js AI prompt use Server Actions or Route Handlers for AI calls?

Chat goes through a Route Handler that returns a UI message stream, because useChat posts to an endpoint and reads the stream back. One-shot generation a form waits for, like a summary or a classification with Output.object, goes in a Server Function. New work stays off the experimental AI SDK RSC package.

Which model providers does the Next.js AI prompt work with?

Any provider the AI SDK supports. The agent follows the project's choice: AI Gateway model strings in provider/model form with AI_GATEWAY_API_KEY, or a provider package such as @ai-sdk/anthropic. It keeps the model in one server module and never invents a model id, so switching providers is a one-line change.

4.9 out of 5 from 150+ developers

Rules teach it. The MCP equips it.

Every component, block and icon, installed by your AI agent on your stack. The prompts stay free.

Get Pro
  • Cancel anytime
  • Keep what you've shipped