September 20, 2026 · 9 min read

Streaming AI Responses: SSE, WebSockets, and the Right Transport

Streaming is a behavior, not a protocol. Here is how SSE, WebSockets, chunked HTTP, and Ollama’s model stream fit together—and how to choose without overengineering.

Streaming · SSE · WebSockets · Ollama · System Design


An editorial illustration of one-way and two-way AI data streams

An AI response feels fast when the user sees useful output early, not merely when the last token arrives quickly. That makes transport design part of the product experience.

The crucial distinction is simple: streaming describes how results arrive; SSE and WebSockets are two of the mechanisms that can carry them.

Ollama’s native streaming API currently emits newline-delimited JSON. In the architecture below, the application gateway consumes that model stream and translates it into SSE for the browser.

Streaming is a behavior

Streaming simply means the server does not wait until the entire answer is ready before sending something back to the user.

Suppose your application asks Ollama:

Explain how a mortgage works.

Without streaming, the flow looks like this:

User sends question
        |
        v
Server starts generating
        |
        |  waits...
        |  waits...
        |  waits...
        |
        v
Entire answer completed
        |
        v
Browser receives everything at once

The user may stare at an empty screen for five or ten seconds.

With streaming, the server starts sending pieces as soon as they are generated:

User sends question
        |
        v
Server starts generating
        |
        +--> "A"
        +--> " mortgage"
        +--> " is"
        +--> " a loan"
        +--> " used"
        +--> " to purchase..."

The user starts seeing the answer immediately:

A mortgage is a loan used to purchase...

This is exactly the behavior you see in ChatGPT when words appear progressively.

Streaming is therefore not really a communication protocol by itself. It is a behavior: instead of sending one complete response, the server sends multiple pieces over time.

Those pieces are often called chunks, events, tokens, or messages depending on the implementation.

For AI applications, streaming is especially useful because model generation can take several seconds. Even if the full answer takes ten seconds, the first words might be available in half a second.

So the perceived performance becomes much better.

Without streaming:

10 seconds silence

whole answer

With streaming:

0.5 sec

first words

more words

more words

finished at 10 sec

The total processing time might still be ten seconds. The user experience is simply much better.


Server-Sent Events

Server-Sent Events, usually abbreviated as SSE, is one specific way of implementing streaming over HTTP.

The easiest way to understand SSE is:

Browser makes one HTTP request.

Server keeps that HTTP response open.

Server sends new pieces whenever something becomes available.

Imagine your browser sends:

GET /api/chat/stream

Instead of responding once and closing the connection, the server keeps it open:

Browser                           Server

   |                                |
   |------ request ---------------->|
   |                                |
   |<------ "A mortgage" -----------|
   |                                |
   |<------ " is a loan" -----------|
   |                                |
   |<------ " used to buy" ---------|
   |                                |
   |<------ " property." -----------|
   |                                |
   |<------ DONE -------------------|
   |                                |
   connection closes

That is SSE.

Technically, the server responds using:

Content-Type: text/event-stream

and sends events such as:

data: A mortgage

data: is a loan

data: used to buy

data: property.

The browser receives those events one by one.


A Real AI Use Case

Suppose you build this application:

Company Knowledge Assistant

The user asks:

What is our production deployment procedure?

Your frontend sends:

POST /api/chat

to your AI Gateway.

Your Gateway performs RAG:

Question
   |
   v
Embedding search
   |
   v
Find deployment policy
   |
   v
Send context + question to Ollama

Ollama starts producing:

Before
deploying
to
production,
the
service
owner...

Your backend does not need to wait for Ollama to finish.

Instead, the flow can become:

Ollama
   |
   | stream chunks
   v
AI Gateway
   |
   | SSE
   v
Browser

So perhaps Ollama produces:

"Before"

Your Gateway immediately sends an SSE event:

data: Before

Then Ollama produces:

" deploying"

The Gateway sends:

data: deploying

The browser keeps appending them.

The user sees:

Before deploying to production, the service owner...

while Ollama is still generating the rest.


Streaming and SSE Are Not the Same Thing

This distinction is important.

Streaming is the general concept.

SSE is one technology you can use to implement streaming.

Think about transportation.

Streaming = transporting people

SSE       = using a bus
WebSocket = using a train
HTTP chunking = using a car

The goal is movement. The mechanism is different.

Similarly:

Streaming

can be implemented using:

    SSE
    WebSocket
    HTTP chunked responses
    gRPC streaming

So when someone says:

"Our application supports streaming."

you still don’t know exactly how it is implemented.

When they say:

"We stream responses using SSE."

now you know the transport mechanism.


Why SSE Works So Well for AI Chat

AI generation usually follows this pattern:

Client asks something
        |
        v
Server produces lots of output
        |
        v
Client receives output

Notice that most traffic after the request goes in one direction:

Server ---> Client

That is exactly what SSE is designed for.

The browser sends one initial request, and then the server keeps pushing updates back.

An AI response naturally fits this pattern:

User:
Explain Kubernetes.

Server:
"Kubernetes..."
"is..."
"a container..."
"orchestration..."
"platform..."

Therefore SSE is commonly a very good choice for AI text generation.


Another Good SSE Use Case: Job Progress

Imagine the user uploads 5,000 documents for indexing.

The process may take several minutes.

The browser could receive:

data: {"progress":10}

data: {"progress":25}

data: {"progress":51}

data: {"progress":78}

data: {"progress":100}

Your screen can display:

Indexing documents: 78%

Again, communication mainly flows from:

Server ---> Browser

SSE fits very nicely.


Another Example: Deployment Status

Suppose your DevOps application starts a deployment.

Instead of the frontend repeatedly asking:

Are you done?
Are you done?
Are you done?
Are you done?

the browser opens an SSE connection.

Then the backend sends:

Build started

Build successful

Docker image created

Deploying to Kubernetes

Pods starting

Health checks successful

Deployment complete

This is a natural SSE application.


Why Not Just Keep Calling the Server?

Without streaming, programmers sometimes implement polling.

The browser asks every two seconds:

GET /deployment/status

Then again:

GET /deployment/status

Then again:

GET /deployment/status

This is called polling.

Conceptually:

Browser ---> Any update?
Server  ---> No.

Browser ---> Any update?
Server  ---> No.

Browser ---> Any update?
Server  ---> Yes.

Browser ---> Any update?
Server  ---> Yes.

This produces unnecessary traffic and can introduce delay.

SSE changes the model:

Browser:
Tell me whenever something changes.

Server:
Okay.

Server:
Build started.

Server:
Build complete.

Server:
Deployment started.

Server:
Deployment complete.

That is usually much cleaner.


Where SSE Is Less Suitable

SSE is mostly one-directional.

The important direction is:

Server ---> Client

The browser can still send ordinary HTTP requests separately, but the SSE connection itself is primarily server-to-client.

Suppose you are building a multiplayer game.

You might need communication like:

Client ---> move player
Server ---> opponent moved
Client ---> fire weapon
Server ---> health changed
Client ---> send position
Server ---> new world state

Now communication is happening constantly in both directions.

SSE is less natural here.

WebSocket is usually better.


WebSocket Compared with SSE

A WebSocket creates a persistent two-way connection:

Client <==========> Server

Both sides can send messages whenever they want.

SSE is more like:

Client -----------> Server
        initial HTTP request

Client <=========== Server
        continuous events

A simple way to remember it is:

SSE:
Server talks continuously.

WebSocket:
Both sides talk continuously.

For an Ollama chat application, SSE is often sufficient because the conversation usually looks like:

User sends one question
        |
        v
Server streams one answer

When the answer finishes, the next user message becomes another ordinary request.


When I Would Choose SSE

For applications you are likely to build, I would strongly consider SSE for things like:

LLM response streaming
RAG answer streaming
agent execution updates
document-processing progress
background job status
build/deployment logs
notification streams
monitoring events

For example, an agent might generate:

Searching documents...

Found 6 relevant documents...

Checking project database...

Calling cost calculator...

Analyzing results...

Preparing answer...

SSE can continuously send these status updates to the browser.


When I Would Choose WebSocket Instead

I would lean toward WebSocket when both sides need frequent, independent communication.

Examples include:

multiplayer games
collaborative document editing
live trading interfaces
interactive terminals
voice assistants
real-time audio
real-time telemetry control
bidirectional agent interfaces

A voice AI application is a particularly good example.

The client might continuously send:

audio
audio
audio
audio

while the server simultaneously sends:

transcript
audio response
status
tool results

That is genuinely bidirectional.

WebSocket makes more sense.


A Practical Ollama Architecture

For a normal local AI assistant, I would probably use this:

Browser
   |
   | POST question
   v
FastAPI / Go Gateway
   |
   | request
   v
Ollama
   |
   | streaming tokens
   v
Gateway
   |
   | SSE
   v
Browser

The browser might send:

Explain our deployment policy.

The Gateway sends the request to Ollama.

Ollama streams:

"The"
" deployment"
" policy"
" requires"
...

Your Gateway receives those pieces and immediately forwards them through SSE.

The browser appends them into the chat window.

So there are actually two streams:

Ollama
   |
   | model stream
   v
Gateway
   |
   | SSE stream
   v
Browser

That is a very common and clean architecture.

The simplest way to remember the whole thing is this:

Streaming
= Send results gradually instead of waiting for everything.

SSE
= A simple HTTP mechanism for the server to continuously
  send those results to the browser.

WebSocket
= A persistent connection where both client and server
  can continuously send messages.

For a typical Ollama text-chat or RAG application, SSE is usually the first approach I would consider because the dominant flow is server-to-browser streaming, which is exactly what SSE is good at.

The decision in one sentence

Use the simplest transport that matches the direction of the conversation. If the browser sends one request and mostly receives a sequence of updates, SSE is usually the cleanest fit. If both sides must send independent messages continuously, use WebSockets. If incremental output adds no product value, return ordinary HTTP and keep the system simpler.

Continue the series

Official references