Vercel AI SDK

The Vercel AI SDK is the most-used TypeScript LLM toolkit — a vendor-neutral abstraction over OpenAI, Anthropic, Google, xAI, Mistral, Cohere, Groq, Together AI, Fireworks, DeepInfra, Replicate, Amazon Bedrock, Azure OpenAI, Google Vertex, Ollama, and OpenRouter, plus React/Vue/Svelte/Solid hooks for streaming chat UIs. It ships in three layers — Core (functions you call from server code), UI (framework hooks for the client), and RSC (React Server Component utilities for streaming UI components from the model) — and pairs with Vercel AI Gateway (Vercel-hosted router with caching, fallbacks, and analytics across providers). Designed for Vercel Functions but works anywhere — the SDK has no Vercel dependencies.

See also

1. Install

pnpm i ai                         # core SDK
pnpm i @ai-sdk/anthropic          # provider plugin
pnpm i @ai-sdk/openai             # another provider plugin
pnpm i zod                        # for tool/object schemas

The unified model string syntax (e.g. "anthropic/claude-sonnet-4-6") requires the relevant provider plugin to be installed.

2. Core — server-side functions

Per sdk.vercel.ai/docs/ai-sdk-core. Four primary functions:

FunctionPurposeReturns
generateTextSingle completion, full response{ text, toolCalls, finishReason, usage }
streamTextStreaming completionStream object with .toDataStreamResponse(), .textStream, .fullStream
generateObjectType-safe structured output{ object, finishReason, usage }
streamObjectStreaming structured outputStream of partial objects
embed / embedManyText embedding{ embedding, usage }
generateImageImage generation{ image, finishReason }

2.1 generateText

import { generateText } from "ai";
 
const { text, usage, finishReason } = await generateText({
  model: "anthropic/claude-sonnet-4-6",
  prompt: "Explain CAP theorem in 50 words.",
});
 
console.log(text);
console.log(`Tokens: ${usage.totalTokens}, stop: ${finishReason}`);

Switch providers by changing the model string — same generateText call works across providers:

// Anthropic
await generateText({ model: "anthropic/claude-opus-4-7", prompt: "..." });
// OpenAI
await generateText({ model: "openai/gpt-5.2", prompt: "..." });
// Google
await generateText({ model: "google/gemini-3.0-pro", prompt: "..." });
// xAI
await generateText({ model: "xai/grok-4", prompt: "..." });
// Local via Ollama
await generateText({ model: "ollama/llama3.3", prompt: "..." });

The unified model string requires the provider package installed. The string syntax was added in AI SDK 5 (mid-2025); older code uses explicit provider imports:

import { anthropic } from "@ai-sdk/anthropic";
const { text } = await generateText({
  model: anthropic("claude-sonnet-4-6"),
  prompt: "...",
});

2.2 streamText

The bread-and-butter API for AI chat UIs:

import { streamText } from "ai";
 
const result = streamText({
  model: "anthropic/claude-sonnet-4-6",
  messages: [
    { role: "system", content: "You are a coding tutor." },
    { role: "user", content: "Explain async/await." },
  ],
  maxTokens: 1024,
  temperature: 0.3,
});
 
// Server (in a Vercel Function):
return result.toDataStreamResponse();
 
// Or consume tokens server-side:
for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}

2.3 generateObject — type-safe structured output

Pair with Zod for end-to-end type safety:

import { generateObject } from "ai";
import { z } from "zod";
 
const recipeSchema = z.object({
  name: z.string(),
  prep_minutes: z.number(),
  ingredients: z.array(z.object({
    name: z.string(),
    amount: z.string(),
  })),
  steps: z.array(z.string()),
});
 
const { object } = await generateObject({
  model: "anthropic/claude-sonnet-4-6",
  schema: recipeSchema,
  prompt: "Generate a lasagna recipe.",
});
 
// `object` is typed as inferred Zod schema
console.log(object.name);              // string
console.log(object.ingredients[0].name); // string

Under the hood: the SDK uses the model’s native structured-output mode (JSON schema mode on OpenAI, tool-use-as-schema on Anthropic, function-calling on others). Falls back to prompted JSON if the model doesn’t support it.

2.4 streamObject — streaming structured output

Useful for showing incremental progress on long structured generations:

const { partialObjectStream } = streamObject({
  model: "anthropic/claude-sonnet-4-6",
  schema: recipeSchema,
  prompt: "Generate a complex 50-step recipe.",
});
 
for await (const partial of partialObjectStream) {
  // `partial` is the partially-constructed object as it streams in
  console.log(JSON.stringify(partial, null, 2));
}

2.5 Tool use

Define tools with Zod schemas + an execute function:

import { generateText, tool } from "ai";
import { z } from "zod";
 
const { text, toolCalls, toolResults } = await generateText({
  model: "anthropic/claude-sonnet-4-6",
  prompt: "What's the weather in Paris and London?",
  tools: {
    getWeather: tool({
      description: "Get the current weather for a city.",
      inputSchema: z.object({
        city: z.string().describe("City name"),
        unit: z.enum(["C", "F"]).default("C"),
      }),
      execute: async ({ city, unit }) => {
        const data = await fetchWeather(city, unit);
        return { temperature: data.temp, conditions: data.conditions };
      },
    }),
  },
  // Run multi-step tool-use loop until model returns a final answer
  maxSteps: 5,
});

maxSteps controls the tool-calling loop — model calls tool, SDK executes, returns result, model continues. With Claude/OpenAI/etc. supporting parallel tool use, multiple tools can fire per step.

2.6 Embeddings

import { embed, embedMany } from "ai";
 
const { embedding } = await embed({
  model: "openai/text-embedding-3-small",
  value: "What is CAP theorem?",
});
 
const { embeddings } = await embedMany({
  model: "openai/text-embedding-3-small",
  values: ["text 1", "text 2", "text 3"],
});

3. UI — framework hooks for chat UIs

Per sdk.vercel.ai/docs/ai-sdk-ui. Three primary hooks (React shown; same exists for Vue, Svelte, Solid):

HookPurpose
useChatMulti-turn conversation with auto-streaming
useCompletionSingle completion (form-style)
useObjectStreaming structured output

3.1 useChat

"use client";
import { useChat } from "@ai-sdk/react";
 
export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading, error } = useChat({
    api: "/api/chat",
    initialMessages: [{ id: "0", role: "system", content: "..." }],
  });
  
  return (
    <div>
      {messages.map((m) => (
        <div key={m.id}>
          <strong>{m.role}:</strong> {m.content}
        </div>
      ))}
      
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Say something..."
          disabled={isLoading}
        />
      </form>
      
      {error && <div>Error: {error.message}</div>}
    </div>
  );
}

Paired with a server route:

// app/api/chat/route.ts
import { streamText } from "ai";
 
export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: "anthropic/claude-sonnet-4-6",
    messages,
  });
  return result.toDataStreamResponse();
}
 
export const runtime = "edge";

The wire format between client and server is automatically managed by toDataStreamResponseuseChat.

3.2 useCompletion

Single-shot completion:

const { completion, input, handleInputChange, handleSubmit, isLoading } = useCompletion({
  api: "/api/completion",
});

3.3 useObject

For streaming structured output to the UI:

const { object, submit, isLoading } = useObject({
  api: "/api/recipe",
  schema: recipeSchema,
});
 
// object is the partial schema-typed object as it streams in

4. RSC — React Server Components AI elements

Per sdk.vercel.ai/docs/ai-sdk-rsc. The ai/rsc module lets server code stream React components, not just text:

// app/actions.ts (server action)
"use server";
import { streamUI } from "ai/rsc";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
 
export async function submit(message: string) {
  const result = await streamUI({
    model: anthropic("claude-sonnet-4-6"),
    messages: [{ role: "user", content: message }],
    text: ({ content }) => <p>{content}</p>,
    tools: {
      showWeather: {
        description: "Display weather UI",
        parameters: z.object({ city: z.string() }),
        generate: async function* ({ city }) {
          yield <div>Loading weather for {city}...</div>;
          const data = await fetchWeather(city);
          return <WeatherCard data={data} />;
        },
      },
    },
  });
  
  return result.value;   // a React server component tree
}

Used in conjunction with useUIState and useActions for managing the UI on the client side. Powerful for AI apps that render rich UI (cards, charts, forms) generated by the model.

5. Provider plugins — the catalog

Per sdk.vercel.ai/docs/foundations/providers-and-models. Each provider has a package + a unified-string syntax:

ProviderPackageString prefixNotes
Anthropic@ai-sdk/anthropicanthropic/Native Claude models
OpenAI@ai-sdk/openaiopenai/GPT-5.x, GPT-4.x, embeddings, image gen
Google Generative AI@ai-sdk/googlegoogle/Gemini
Google Vertex@ai-sdk/google-vertexgoogle-vertex/Same Gemini via Vertex auth
xAI@ai-sdk/xaixai/Grok
Mistral@ai-sdk/mistralmistral/Mistral-hosted
Cohere@ai-sdk/coherecohere/Cohere-hosted
Groq@ai-sdk/groqgroq/Open-weight models on LPUs — fastest inference
Together AI@ai-sdk/togetheraitogetherai/Open-weight catalog
Fireworks@ai-sdk/fireworksfireworks/Open-weight catalog
DeepInfra@ai-sdk/deepinfradeepinfra/Open-weight catalog
Replicate@ai-sdk/replicatereplicate/Open-weight + image/video models
Amazon Bedrock@ai-sdk/amazon-bedrockamazon-bedrock/Claude, Llama, Nova on AWS
Azure OpenAI@ai-sdk/azureazure/OpenAI on Azure
Ollamaollama-ai-provider (community)ollama/Local models
OpenRouter@openrouter/ai-sdk-provider (community)openrouter/200+ models behind one API

All providers expose the same surface — generateText, streamText, etc., where supported. Some advanced features (extended thinking, prompt caching, computer use) require provider-specific options:

import { anthropic } from "@ai-sdk/anthropic";
 
const { text } = await generateText({
  model: anthropic("claude-sonnet-4-6"),
  prompt: "Solve this problem step by step.",
  providerOptions: {
    anthropic: {
      thinking: { type: "enabled", budgetTokens: 4096 },
      cacheControl: { type: "ephemeral" },
    },
  },
});

6. AI Gateway

Per vercel.com/docs/ai-gateway. Vercel-hosted router that sits between your code and the provider APIs:

// Without AI Gateway
const result = streamText({
  model: anthropic("claude-sonnet-4-6"),
  ...
});
 
// With AI Gateway
const result = streamText({
  model: "anthropic/claude-sonnet-4-6",   // ← gateway intercepts
  ...
});

Features:

  • Cross-provider auth — set provider keys once in the Vercel dashboard; AI Gateway uses them. No need to ship keys to your functions.
  • Caching — automatic for deterministic requests (temperature 0).
  • Rate limiting — per-team or per-project.
  • Fallback chain — declare priority order across providers. If Anthropic rate-limits, fall back to OpenAI.
  • Analytics — per-provider, per-model spend + latency + token usage in Vercel Observability.

Pricing: $0 (passes through provider costs). Vercel makes money on the surrounding usage.

Fallback example:

const result = streamText({
  model: "anthropic/claude-sonnet-4-6",
  fallbackModels: [
    "openai/gpt-5.2",
    "google/gemini-3.0-pro",
  ],
  ...
});

7. Stop conditions

Per sdk.vercel.ai/docs/ai-sdk-core/tool-calling. Control when streaming stops:

import { streamText, stepCountIs, hasToolCall } from "ai";
 
const result = streamText({
  model: "...",
  messages,
  tools: { ... },
  stopWhen: [
    stepCountIs(10),               // stop after 10 tool-use steps
    hasToolCall("finalAnswer"),    // stop when the model calls this tool
  ],
});

8. Error handling

import { generateText, AISDKError, APICallError, NoSuchToolError } from "ai";
 
try {
  const result = await generateText({ ... });
} catch (err) {
  if (APICallError.isInstance(err)) {
    console.log(`API error ${err.statusCode}: ${err.responseBody}`);
  } else if (NoSuchToolError.isInstance(err)) {
    console.log(`Model called unknown tool: ${err.toolName}`);
  } else if (AISDKError.isInstance(err)) {
    console.log(`SDK error: ${err.message}`);
  } else {
    throw err;
  }
}

9. Telemetry — OpenTelemetry

The SDK emits OTel spans for every model call. Configure once:

import { generateText } from "ai";
 
const { text } = await generateText({
  model: "...",
  prompt: "...",
  experimental_telemetry: {
    isEnabled: true,
    functionId: "summarize-doc",   // appears in traces
    metadata: { userId: "u_7281", env: "prod" },
  },
});

In Vercel, these spans flow into Observability automatically. Outside Vercel, configure an OTel exporter (e.g. Sentry, Datadog) and the SDK’s spans show up there.

10. Vercel-specific deployment patterns

10.1 Edge runtime + streaming

// app/api/chat/route.ts
export const runtime = "edge";          // V8 isolate
export const maxDuration = 25;          // streaming max on Edge
 
export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: "anthropic/claude-sonnet-4-6",
    messages,
  });
  return result.toDataStreamResponse();
}

10.2 Node.js runtime + Fluid Compute (for heavier processing)

// app/api/agent/route.ts
export const runtime = "nodejs";        // Node 22 — supports more deps
export const maxDuration = 300;         // 5min for long agent loops
 
export async function POST(req: Request) {
  // Multi-step agent with tools that hit DBs
  const { text } = await generateText({
    model: "anthropic/claude-sonnet-4-6",
    messages: ...,
    tools: { ... },                     // tools using Node-specific libs
    maxSteps: 20,
  });
  return Response.json({ result: text });
}

11. AI SDK version history (high-level)

  • v3 (2024) — original release, function-per-provider API.
  • v4 (mid-2025) — unified model strings, AI Gateway integration, streamObject GA.
  • v5 (early 2026) — RSC GA, computer-use tool integration, MCP client support, stop conditions API.

Further reading