The single most important streaming difference
Cloud APIs (OpenAI, Anthropic, Google) stream over Server-Sent Events (SSE) — each chunk is data: {json}\n\n. Ollama streams over newline-delimited JSON (NDJSON) — each chunk is just {json}\n. No data: prefix, no double newlines.
If you point an SSE parser at Ollama, it sees one giant blob and waits forever for a data: that never comes. If you point a JSON parser at Ollama, it reads one whole streaming response as a single token and crashes when it hits the second {.
The shape of one NDJSON line
Each line is a complete, parseable JSON object. The interesting fields:
message.content— text delta (one or a few tokens).done— boolean.falsefor incremental chunks,trueon the final chunk.- Final chunk only: timing fields (
total_duration,eval_count,eval_duration, etc.) for performance metrics.
Why Ollama chose NDJSON
NDJSON is simpler to produce server-side, simpler to parse client-side (split on newline, JSON-parse each line), and doesn't require the SSE keep-alive comment ritual. The cost is that you have to know it's not SSE before you reach for an SSE library.