Streaming responses as they generate
Tokens arrive one at a time — streaming shows them as they land instead of making users wait. Learn server-sent events, chunk shape, and when streaming is the wrong choice.
The model writes one token, then the next. A normal request hides that: it waits for the very last token before returning anything. For a 300-token answer, that's several seconds of staring at nothing. hands you each piece as soon as it is written.
The same request, a different transport
streamGenerateContent with ?alt=sse returns : an HTTP response that stays open while pieces of the answer arrive. Each piece is a line starting with data: followed by JSON, and that JSON is a normal response holding a small slice of text.
data: {"candidates":[{"content":{"parts":[{"text":"A large "}]}}]}
data: {"candidates":[{"content":{"parts":[{"text":"language model "}]}}]}
data: {"candidates":[{"content":{"parts":[{"text":"predicts..."}]},"finishReason":"STOP"}]}So every chunk has the same shape as a full response. gemini.text(chunk) works on each one exactly as it does on a complete reply. Your code joins the pieces together.
const result = await gemini.streamGenerateContent({
contents: "Explain tokens in two sentences.",
onChunk: (chunk) => {
console.log(gemini.text(chunk)); // fires as each piece arrives
},
});
result.text; // the whole answer, reassembled
result.chunkCount; // how many frames arrivedUnder the hood — What are server-sent events?
Ordinary HTTP is one request, one response, connection closed. Server-sent events keep the response open and let the server push data down it over time, as a stream of text frames. Each frame is a line starting data:, and a blank line marks the end of that frame.
It is deliberately simpler than a : one direction only (server → client), plain HTTP with no protocol upgrade, and automatic reconnection in browsers. That is a perfect fit here, because you have nothing to send back mid-generation — you only need to receive.
The ?alt=sse on the URL is what asks Gemini for this format. Without it the same endpoint returns a JSON array, which you would have to wait for in full — defeating the point.
What streaming does and doesn't buy you
Normal request
Streaming
- The first words appear much sooner (). That is the whole benefit: the app feels much faster.
- Total time is unchanged. The last token arrives when it always would have. You are not making anything faster, only visible sooner.
- Cost is identical. Same tokens, same bill.
Handling failure mid-stream
A stream can start fine and then stop early: a safety block, a token limit, a dropped connection. You have already shown the user some text, so you can't just swap in an error page. Check the on the last chunk, and if it isn't STOP, add a short note below the text instead of replacing it.
Key takeaways
- Streaming shows the answer while it is written. Total time and cost stay the same.
- Every chunk has the same shape as a full response, so gemini.text(chunk) works on each one.
- Stream when people read the answer. Use a normal call when code needs the complete answer, like JSON.
Sign in to run the exercise
Reading is free. Writing code here needs an account so we have somewhere to keep your Gemini key and the +30 XP you are about to earn.