← Course index

Why streaming beats waiting

Users perceive speed when tokens arrive incrementally — even if total latency is similar.

Day 3: Streaming text·~16 min read

On this page

After this topic

You will be able to explain why ChatGPT types instead of spinning — and why that is not a UI trick. You will know which latency number users feel, which number you pay for, and when waiting is still the right call.

The spinner is lying

Time-to-first-token is when the first word appears. Time-to-last-token is when the model is done. Users judge the first. Your bill is the second.

You already know generateText. Streaming is the same call — same model, same messages — but the UI updates on every token instead of once at the end.

A chat that blocks until the full reply is ready feels broken, even when the model is fast. The user sent a message. They are looking at a spinner. Meanwhile the model may already have the first sentence. You are hiding progress that already exists.

Streaming sends each token to the browser as the model produces it — the same pattern every consumer chat product uses. Total time can be similar. Perceived time is not. A 4-second wait with words at 400ms feels faster than a 3-second wait with a spinner, because the first number is “the product is working” and the second is “is it stuck?”

This only works because of Day 1: the model cannot skip to the end of the paragraph. Token two does not exist until token one is chosen. You might as well show them in that order.

Wait versus stream. generateText gives you one string when the model is done. streamText paints tokens as they arrive. Same request, different delivery.

What actually moves

On the server you call streamText instead of generateText. The AI SDK opens a stream from the provider (or Gateway), and you turn that into an HTTP response the client hook knows how to read.

On the client, useChat from @ai-sdk/react holds the messages array and appends tokens as they arrive. You do not parse Server-Sent Events yourself. You do not put the API key in this file.

The messages you send are the same array as yesterday. Streaming is delivery, not a different mental model. Tool calls, later, ride the same stream as extra parts on the assistant message.

How a stream reaches the browser. Tokens leave the provider as they exist. Your Route Handler forwards them. useChat paints them. Nothing waits for the last token.
  • ServerstreamText → toUIMessageStreamResponse()
  • WireServer-Sent Events (chunks of UI messages, not a finished JSON blob)
  • ClientuseChat + DefaultChatTransport({ api: '/api/chat' })
  • Same getModel() as generateText. Same messages array. History still lives where you stored it.

What “fast” actually means

Two clocks matter. Time-to-first-token (TTFT) is how long until the first word paints. That is the clock users feel. Time-to-last-token is how long until the model stops. That is closer to what you pay for, plus a bit of network.

A bigger model is often slower to first token and better at hard instructions. A smaller model is snappier and enough for short copy. Streaming does not make a slow model cheap. It makes a slow model honest: the user sees work happening.

If the first token takes two seconds, look at cold starts, the route’s region, and whether you stuffed a huge system prompt. Streaming will not hide a 2,000-token preamble.

When not to stream

Scripts, cron jobs, and tests should wait. A stream is harder to assert on. Classification and “extract this object” should wait (or use structured output) so you never render a half-field.

If the answer is one word, streaming buys you nothing. If the answer is a page, it is the difference between a product and a spinner.

You also cannot easily “undo” a streamed sentence the user already read. If you must validate the whole answer before showing it (moderation, a schema), wait, then render once. Streaming is a contract with the user: what they see is the answer, as it is born.

Common questions

Why streaming beats waiting?
Users perceive speed when tokens arrive incrementally — even if total latency is similar.
What will I be able to do after this lesson?
You will be able to explain why ChatGPT types instead of spinning — and why that is not a UI trick. You will know which latency number users feel, which number you pay for, and when waiting is still the right call.
How long does this lesson take?
About 16 minutes of reading. It is a free chapter in the AI SDK Patterns TypeScript course.
When should I not use this?
Scripts, cron jobs, and tests should wait. A stream is harder to assert on. Classification and “extract this object” should wait (or use structured output) so you never render a half-field.

Written by Akash Panchal·Updated August 29, 2026