When you call the Messages API without streaming, the request blocks until the model has finished generating the entire response, then returns one complete JSON object. For a short answer that is fine. For a long answer — a report, a code file, an agent's reasoning — your user stares at a spinner for the full generation time. Streaming changes the delivery model: the API starts sending the response the moment the first tokens exist, in a series of small events, and your application can render each fragment as it arrives. The total time is roughly the same; the perceived time drops dramatically, because the user sees progress within a second or two.
The protocol layer: Server-Sent Events
Under the hood, Claude streaming uses Server-Sent Events (SSE) — a long-lived HTTP response in which the server pushes a sequence of text-encoded events down a single connection. SSE is a plain web standard: no WebSockets, no special client library required, and it passes through ordinary HTTP infrastructure. Each event in the stream carries a piece of the message being built — the message opening, fragments of text as they are generated, block boundaries, and a final event that closes out the message with metadata such as the stop reason and token usage.
One detail worth knowing if you deploy on AWS: Claude Platform on AWS (the Anthropic-operated service inside AWS) streams using the same SSE format as the first-party Claude API — not the AWS EventStream encoding used elsewhere in the AWS ecosystem. Code written against the Claude API's stream shape carries over. Streaming itself is core Messages API functionality and is available on all four third-party platforms: Claude Platform on AWS, Amazon Bedrock, Google Vertex AI, and Microsoft Foundry.
What the SDK adds on top
You could consume the SSE feed with raw HTTP, but you would be hand-parsing event frames and reassembling deltas yourself. The official SDKs wrap the protocol in two ergonomic layers:
Iterators. The streaming call returns an object you can loop over with your language's native iteration construct — a for loop in Python, for await in TypeScript. Each iteration yields the next event (or, with convenience accessors, just the next text fragment), and the loop ends when the message is complete.
Event callbacks and accumulation. The SDKs also expose listener-style hooks for reacting to specific event types, and helpers that quietly accumulate every delta so that, when the stream ends, you can ask for the fully assembled final message — with the complete content, stop reason, and usage — without having stitched it together yourself. We cover those in SDK streaming helpers.
The non-streaming baseline in Python looks like this (the client reads ANTHROPIC_API_KEY from the environment automatically):
from anthropic import Anthropic
client = Anthropic()
message = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
)
The streaming variant is exposed on the same messages surface as an iterator-based interface; the exact helper names and event types are documented in the Python SDK repository and its counterparts for other languages. The same pattern works unchanged against third-party platforms by swapping the client class — for example AnthropicAWS() for Claude Platform on AWS or AnthropicVertex(project_id="...", region="global") for Vertex AI.
When to stream — and when not to
| Situation | Recommendation |
|---|---|
| Chat UI, coding assistant, anything a human watches | Stream — perceived latency is the product |
| Long generations that risk network timeouts | Stream — a live connection is easier to keep healthy than one long silent request |
| Backend pipeline that only consumes the finished text | Either works; non-streaming is simpler code |
| High-volume offline jobs | Consider batch processing instead, where your platform offers it |
Two practical cautions. First, error handling changes shape: a stream can fail midway, after you have already rendered partial text, so plan for retry-and-replace rather than assuming all-or-nothing. Second, if you need the complete message for logging, moderation, or storage, use the SDK's final-message accumulation rather than concatenating fragments by hand — it is easy to drop non-text blocks otherwise.
Where to go next
See streaming in TypeScript for the async-iterator flavor, streaming to browser clients for the proxy pattern, and the feature matrix for what else each platform supports.