Vercel AI SDK Basics
8 examples to get you started with the Vercel AI SDK in Next.js - 5 basic and 3 intermediate.
You will install the packages, stream a chat with useChat, render message parts, add a tool, and set duration/runtime knobs for real deploys.
Prerequisites
- Node.js 20+ recommended (22+ if following the latest AI SDK quickstarts)
- A Next.js App Router project
- A model API key (Vercel AI Gateway, OpenAI, OpenRouter, or another AI SDK provider)
pnpm create next-app@latest my-ai-app
cd my-ai-app
pnpm add ai @ai-sdk/react zod
# optional direct provider package:
# pnpm add @ai-sdk/openai# .env.local (names vary by provider - verify at build)
AI_GATEWAY_API_KEY=...
# or OPENAI_API_KEY=... / OPENROUTER_API_KEY=...Pin ai to the major you target (this guide assumes AI SDK 6 APIs; helpers may rename - verify at build).
Basic Examples
1. Minimal Streaming Chat Route
Create app/api/chat/route.ts that streams model output as a UI message stream.
import {
streamText,
convertToModelMessages,
type UIMessage,
} from "ai";
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: "openai/gpt-4o-mini", // gateway string or provider model - verify at build
messages: await convertToModelMessages(messages),
instructions: "You are a concise product assistant.",
});
return result.toUIMessageStreamResponse();
}UIMessage[]is the client history shape; convert before calling the model.streamTextreturns a result you expose as a UI message stream response.- If your version uses
createUIMessageStreamResponse+toUIMessageStream, swap the return line - verify at build.
Related: The Vercel AI SDK Mental Model: Streaming UI Meets Agent Loops
2. Wire useChat in a Client Page
"use client";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import { useState } from "react";
export default function ChatPage() {
const [input, setInput] = useState("");
const { messages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
});
return (
<div>
{messages.map((message) => (
<div key={message.id}>
<strong>{message.role}: </strong>
{message.parts.map((part, i) =>
part.type === "text" ? <span key={i}>{part.text}</span> : null,
)}
</div>
))}
<form
onSubmit={(e) => {
e.preventDefault();
if (!input.trim()) return;
sendMessage({ text: input });
setInput("");
}}
>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={status !== "ready"}
placeholder="Say something..."
/>
<button type="submit" disabled={status !== "ready"}>
Send
</button>
</form>
</div>
);
}- Prefer rendering
message.partsover a single content string. sendMessageis the AI SDK 5+/6 chat send path; older tutorials usedhandleSubmit+ controlledinputfrom the hook.DefaultChatTransportdefaults often target/api/chateven when omitted - be explicit in multi-API apps.
3. Show Status, Stop, and Retry
const { messages, sendMessage, status, stop, error, regenerate } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
});
// In JSX:
{(status === "submitted" || status === "streaming") && (
<button type="button" onClick={() => stop()}>
Stop
</button>
)}
{error && (
<button type="button" onClick={() => regenerate()}>
Retry
</button>
)}submittedmeans the request left but chunks may not have started.streamingmeans parts are still arriving.- Show a generic error string to users; log details server-side only.
4. Add One Server Tool
import { streamText, tool, convertToModelMessages, isStepCount } from "ai";
import { z } from "zod";
const result = streamText({
model: "openai/gpt-4o-mini",
messages: await convertToModelMessages(messages),
stopWhen: isStepCount(5),
tools: {
getWeather: tool({
description: "Get a weather summary for a city",
inputSchema: z.object({
city: z.string().describe("City name"),
}),
execute: async ({ city }) => ({
city,
summary: "sunny",
tempC: 22,
}),
}),
},
});inputSchemais what the model sees and what the SDK validates.executeruns server-side when present.stopWhen: isStepCount(n)bounds multi-step tool loops (helper name verify at build).
5. Render a Tool Part as UI
{message.parts.map((part, i) => {
if (part.type === "text") return <span key={i}>{part.text}</span>;
if (part.type === "tool-getWeather") {
if (part.state === "input-available") return <div key={i}>Loading weather…</div>;
if (part.state === "output-available") {
return (
<pre key={i}>{JSON.stringify(part.output, null, 2)}</pre>
);
}
}
return null;
})}- Tool part types are often
tool-${toolName}. - States such as
input-availableandoutput-availabledrive loading vs result UI. - Expand into real components in the generative UI guide.
Intermediate Examples
6. System Instructions and Model Provider Package
import { openai } from "@ai-sdk/openai";
import { streamText, convertToModelMessages } from "ai";
const result = streamText({
model: openai("gpt-4o-mini"),
instructions:
"Answer in short bullets. If you lack data, say you do not know.",
messages: await convertToModelMessages(messages),
});- String model ids via AI Gateway and provider instances are both valid - pick one convention per app.
- Keep secrets only on the server; never import provider keys into client components.
7. Edge Runtime for Low-Latency Chat
export const runtime = "edge";
export const maxDuration = 30;
// same streamText handler body as example 1- Edge avoids full Node APIs; confirm every dependency is edge-safe.
- Streaming still has platform duration limits; start the response promptly.
- Prefer Node runtime when you need heavy SDKs, file system, or long multi-tool work.
8. Client Transport with Headers (Auth Sketch)
const { messages, sendMessage } = useChat({
transport: new DefaultChatTransport({
api: "/api/chat",
headers: {
// Prefer cookie sessions; tokens only if your auth design requires them
"X-Request-Source": "web-chat",
},
}),
});- Authenticate on the server from cookies/session before running tools.
- Do not trust client-supplied user ids in the JSON body for authorization.
- For Python backends, point
apiat a proxy route that forwards the stream.
Related: Integrating Pydantic AI or LangGraph Behind an AI SDK Frontend
Related
- The Vercel AI SDK Mental Model: Streaming UI Meets Agent Loops - architecture
- Tool Calling and UI Generation with the AI SDK - tool UI depth
- AI SDK 6's Tool-Approval States for Human-in-the-Loop Agents - approvals
- Deploying an AI SDK Agent to Vercel Edge Functions - deploy recipe
- Vercel AI SDK Best Practices - production checklist
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.