Build radar
Sources 33Updates always the freshest
0 Newsletter
Animated illustration for: Vercel AI SDK: your first streaming chat in TypeScript
Create · JavaScript & Vercel AI SDK · Guide · 9 min read

Vercel AI SDK: your first streaming chat in TypeScript

The AI SDK is a TypeScript toolkit for model apps. A minimal chat: a server route with streamText, a component with useChat, and pitfalls.

In short
  • AI SDK Core unifies model calls, and AI SDK UI gives hooks for chat interfaces.
  • A chat consists of a server route with streamText and a component with useChat.
  • Keep keys on the server, set limits and add error and status handling.

If you write TypeScript and want to add a chat with a model to an application, the shortest way is through a ready toolkit. The AI SDK describes itself as a TypeScript toolkit for building AI applications and agents with React, Next.js, Vue, Svelte, Node.js and others. It standardizes integrating models of different providers, so you do not have to write separate code for each. The documentation names the main parts: AI SDK Core, a unified API for generating text, structured objects, tool calls and building agents, and AI SDK UI, framework-agnostic hooks for chat interfaces.

Two elements of a minimal chat

A chat consists of two parts. On the server side there is a route that accepts messages, calls the model and returns a stream. On the client side there is a component that displays messages and sends new ones. The examples below come from the chatbot documentation in AI SDK UI as of the checking date; this library’s API changes between versions, so compare it with the current documentation before use.

The server route uses the streamText function, which starts generation and returns the result as a stream:

import { convertToModelMessages, createUIMessageStreamResponse, streamText, toUIMessageStream, UIMessage } from 'ai';

export const maxDuration = 30;

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();
  const result = streamText({
    model: "anthropic/claude-sonnet-5.5",
    instructions: 'You are a helpful assistant.',
    messages: await convertToModelMessages(messages),
  });
  return createUIMessageStreamResponse({
    stream: toUIMessageStream({ stream: result.stream }),
  });
}

The component uses the useChat hook, which according to the documentation manages message streaming, input state, status and errors:

'use client';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import { useState } from 'react';

export default function Page() {
  const { messages, sendMessage, status } = useChat({
    transport: new DefaultChatTransport({ api: '/api/chat' }),
  });
  const [input, setInput] = useState('');
  // render messages (message.parts) and a form calling sendMessage({ text: input })
}

The documentation recommends rendering messages through the parts property, which supports different part types: text, a tool invocation and its result. That way you can later extend the same component with tools.

What happens along the way

  1. 01
    TypingThe user sends a message in the form.
  2. 02
    RequestuseChat calls the /api/chat route.
  3. 03
    ModelstreamText starts generating.
  4. 04
    StreamText comes back in pieces.
  5. 05
    InterfaceThe component appends message parts.
  6. 06
    Statussubmitted, streaming, ready or error.

It is worth understanding the statuses, because the behaviour of the interface depends on them. The documentation lists, among others, a state of a message being submitted and a ready state, and in the example the input field is disabled until the status is ready. This is a simple way to avoid sending a second message in the middle of a response.

What to add next

Once the basic chat works, the next steps are predictable. Save conversations in a database so the user can return to them, and decide how long you keep them. Add a system instruction describing the assistant’s role and the limits of its answers. Limit the length of history sent to the model, because sending the whole conversation each time raises cost and latency. Only then add tools, search over documents or structured data generation. Each of these elements is worth adding one at a time and checking on a set of sample conversations, so you know which one changed the behaviour.

Pitfalls and good practice

What to watch out for in a first chat
RiskWhat to do
API keyA leak if it lands in client codeKeep it in server environment variables
CostEndpoint abuse and long conversationsLimits on requests, context length and spending
ErrorsInterrupted stream, provider limitHandle the error status and allow a retry
Model outputUntrusted data shown in the interfaceEscape it and never execute output as code
PrivacySensitive data in conversationsTell the user what is sent

The most important rule is the API key on the server side only: every visitor sees code in the browser. The second is limits, because a public endpoint with a model and no limits is an invitation to abuse and a bill that will surprise you; I write about calculating costs in the text Task cost in tokens. The third is treating model output as untrusted data. Tools and input validation are the topic of the next article, Tools and validation in JavaScript, and you will find all materials in the JavaScript and Vercel AI SDK hub.

Last checked: 20 October 2026. The library’s API changes between versions; the code in this text matches the documentation of that day.

Frequently asked questions

Does the AI SDK work only with models of one maker?
No. The documentation describes a unified interface for many model providers, so changing the model usually comes down to changing its identifier.
Why is the answer streamed?
Because the user sees text as it is produced instead of waiting for all of it. The useChat hook manages the stream, the message state and the status.
Where do I keep the API key?
Only on the server side, in environment variables. Code run in the browser is visible to every visitor.
How do I handle an error during a response?
The hook exposes a status and an error, so you can show a message and allow a retry. On the server side limit the time and cost of a single call.

Sources

JavaScript & Vercel AI SDK

Related