Vercel AI SDK: The Complete Guide for Building AI-Powered Next.js Apps

How the Vercel AI SDK unifies LLM providers, the key functions (streamText, generateObject, useChat), Next.js App Router integration, and when to use it over calling APIs directly.

Mahmudul Haque Qudrati — CEO & ML Engineer at Pristren

Mahmudul Haque Qudrati

CEO & ML Engineer

May 18, 2026
10 min read
Vercel AI SDK: The Complete Guide for Building AI-Powered Next.js Apps

The Vercel AI SDK is the fastest way to add streaming AI to a Next.js application. It provides a unified interface for OpenAI, Anthropic, Google, and other providers, handles streaming responses and React state management, and gives you structured output generation with Zod validation. Switching model providers requires changing one import. This guide covers the key APIs you will use in production.

What the SDK Provides

One AI engineering post, weekly

LLM benchmarks, prompt techniques, and token-cost breakdowns — not another AI news roundup.

The SDK solves four problems that come up immediately when building AI applications:

Provider abstraction. The API formats for OpenAI, Anthropic, and Google are all different. The Vercel AI SDK wraps all of them behind a common interface. You write your AI logic once and switch providers by changing the model argument.

Streaming to the client. Streaming requires coordinating server-sent events or chunked responses with client-side state updates. The SDK handles this boilerplate with streamText on the server and useChat/useCompletion on the client.

Structured output. Getting a model to return reliably structured JSON is surprisingly tricky. The SDK's generateObject function uses Zod schemas to validate and type model output, retrying automatically if the model returns invalid structure.

Tool calling. Defining tools, parsing tool call responses, and managing the multi-turn tool use loop is complex to build from scratch. The SDK handles this with a tools parameter and manages the conversation state.

Installation and Provider Setup

snippet
pnpm add ai @ai-sdk/openai @ai-sdk/anthropic

Provider configuration:

snippet
import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";

// OpenAI (uses OPENAI_API_KEY env var)
const model = openai("gpt-4o");

// Anthropic (uses ANTHROPIC_API_KEY env var)
const model = anthropic("claude-3-5-sonnet-20241022");

// Switching providers: change one line

Team workspace

Ship faster with chat, meetings, and projects in one place — Zlyqor.

Start free

streamText: Server-Side Streaming

streamText is the core server-side function. It calls the model and returns a stream you can pipe to the client.

snippet
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: openai("gpt-4o"),
    system: "You are a helpful assistant.",
    messages,
  });

  return result.toDataStreamResponse();
}

toDataStreamResponse() returns a Response object with the correct headers for streaming. The Vercel AI SDK client hooks know how to consume this format.

For non-streaming generation, use generateText:

snippet
import { generateText } from "ai";

const { text } = await generateText({
  model: openai("gpt-4o"),
  prompt: "Summarize this document: ...",
});

useChat: Drop-In Chat Interface

useChat is a React hook that manages message history, input state, and the streaming connection to your API route.

snippet
"use client";
import { useChat } from "ai/react";

export function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } =
    useChat({ api: "/api/chat" });

  return (
    <div>
      <div>
        {messages.map((m) => (
          <div key={m.id}>
            <span>{m.role}: </span>
            <span>{m.content}</span>
          </div>
        ))}
      </div>
      <form onSubmit={handleSubmit}>
        <input value={input} onChange={handleInputChange} />
        <button type="submit" disabled={isLoading}>Send</button>
      </form>
    </div>
  );
}

useChat handles: posting messages to your API route, appending streaming tokens to the last message as they arrive, managing the loading state, and maintaining the full conversation history for multi-turn conversations. This covers the majority of chat UI requirements with minimal code.

useCompletion: Single-Turn Completion

For non-chat use cases (text generation triggered by a user action, not a conversation), useCompletion is simpler than useChat:

snippet
"use client";
import { useCompletion } from "ai/react";

export function SummarizeButton({ document }: { document: string }) {
  const { completion, complete, isLoading } = useCompletion({
    api: "/api/summarize",
  });

  return (
    <div>
      <button onClick={() => complete(document)} disabled={isLoading}>
        Summarize
      </button>
      {completion && <p>{completion}</p>}
    </div>
  );
}

generateObject: Structured Output with Zod

generateObject is one of the most useful SDK functions for production applications. It guarantees the model returns output matching a Zod schema, retrying and coercing as needed.

snippet
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";

const TaskSchema = z.object({
  title: z.string(),
  priority: z.enum(["high", "medium", "low"]),
  estimatedHours: z.number(),
  tags: z.array(z.string()),
});

const { object } = await generateObject({
  model: openai("gpt-4o"),
  schema: TaskSchema,
  prompt: "Extract task details from: " + userMessage,
});

// object is typed as z.infer<typeof TaskSchema>
console.log(object.title);      // string
console.log(object.priority);   // "high" | "medium" | "low"

This is cleaner and more reliable than asking the model to return JSON and parsing it yourself. The SDK handles the system prompt injection that instructs the model to return JSON, parses the response, validates it against the schema, and returns a fully typed object.

Tool Calling

Tools let the model call functions to retrieve information or take actions. The SDK manages the tool call loop:

snippet
import { streamText, tool } from "ai";
import { z } from "zod";

const result = streamText({
  model: openai("gpt-4o"),
  tools: {
    getWeather: tool({
      description: "Get the current weather for a city",
      parameters: z.object({
        city: z.string(),
      }),
      execute: async ({ city }) => {
        const weather = await fetchWeather(city);
        return weather;
      },
    }),
  },
  prompt: "What is the weather in Tokyo?",
  maxSteps: 5,  // allow up to 5 tool call rounds
});

The SDK handles the multi-turn loop: model calls a tool, SDK executes the tool function, result is sent back to the model, model continues. maxSteps prevents infinite loops.

Next.js App Router Integration

The SDK is designed for Next.js App Router. Server-side AI calls work in Server Components, Route Handlers, and Server Actions.

Route Handler pattern (most common):

snippet
// app/api/chat/route.ts
import { streamText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: anthropic("claude-3-5-sonnet-20241022"),
    messages,
  });
  return result.toDataStreamResponse();
}

Server Action pattern:

snippet
// app/actions/ai.ts
"use server";
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";

export async function extractTask(userInput: string) {
  const { object } = await generateObject({
    model: openai("gpt-4o-mini"),
    schema: TaskSchema,
    prompt: userInput,
  });
  return object;
}

Why Use the SDK vs Calling APIs Directly

The case for direct API calls: you have more control, fewer abstractions, and can handle edge cases exactly as you want.

The case for the Vercel AI SDK: the abstractions are well-designed for common cases, and what you give up in control you gain in time. Streaming to the client correctly, handling multi-provider differences, managing the tool call loop, and integrating with React state are all solved problems in the SDK that take meaningful engineering effort to build correctly from scratch.

Use the SDK when you are building on Next.js and your requirements fit the standard patterns. Build directly against provider APIs when you have specific requirements (custom streaming format, unusual tool call patterns, performance constraints) that the SDK's abstractions do not accommodate.

Keep Reading


Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace - chat, projects, time tracking, AI meeting summaries, and invoicing - in one tool. Try it free.

#vercel-ai-sdk#nextjs#streaming#typescript#tool-calling

// discussion

Comments

0/4000
Mahmudul Haque Qudrati — CEO & ML Engineer at Pristren

Mahmudul Haque Qudrati

CEO & ML Engineer

Visionary technologist, software engineer, and machine learning specialist. Founder and CEO of Pristren, directing engineering teams that ship production-grade AI/ML pipelines, mission-critical full-stack applications, and developer tooling. Creator of Zlyqor, the unified team workspace platform. Author of 540+ technical guides and benchmark research reports on large language models, agentic workflows, Model Context Protocol (MCP), and modern web stacks.

PristrenZlyqor