Why You Should Ditch WebSocket for One‑Way Streams: SSE in the LLM Era
The article analyzes real‑time communication options, showing that Server‑Sent Events (SSE) offers native reconnection, simple HTTP‑based architecture, and lower operational overhead than WebSocket, making it the cost‑effective choice for one‑way streaming such as LLM token output.
Why SSE Beats WebSocket for One‑Way Streaming
When modern web apps need to push data to clients—AI LLM token streams, stock tickers, progress bars, or live scores—developers often reach for WebSocket first. The article argues that this habit is outdated for unidirectional text streams and explains why Server‑Sent Events (SSE) is a superior alternative.
WebSocket vs. SSE: Core Feature Comparison
The two protocols differ across six technical dimensions:
Communication direction : WebSocket is full‑duplex; SSE is server‑to‑client only.
Underlying protocol : WebSocket uses a dedicated ws:// or wss:// scheme upgraded from HTTP; SSE uses plain http:// or https:// with the text/event-stream header.
Data format : WebSocket supports UTF‑8 text and native binary (Blob/ArrayBuffer); SSE supports UTF‑8 text only (binary must be Base64‑encoded).
Reconnection : WebSocket has no native reconnection—developers must implement ping/pong and exponential‑backoff logic; SSE provides built‑in browser reconnection with automatic Last-Event-ID replay.
Client API : WebSocket requires new WebSocket() and manual state handling; SSE uses the simple new EventSource() with no library dependencies.
Firewall / gateway friendliness : WebSocket traffic can be blocked by strict corporate firewalls or proxies; SSE traffic looks like ordinary HTTP download streams, so it passes through Nginx, Cloudflare, and enterprise gateways without issue.
Deep Dive into SSE’s Three Core Mechanisms
1. Ultra‑simple protocol: plain‑text stream
SSE sends a continuous HTTP response with Content-Type: text/event-stream. Each event consists of lines of key: value pairs, ending with a double newline ( \n\n) to signal the end of a message.
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
id: 101
event: trade
data: {"symbol": "BTCUSDT", "price": 65000}
id: 102
event: trade
data: {"symbol": "ETHUSDT", "price": 3500}The parsing rules are:
Each line follows key: value.
Data payload starts with data:.
Custom event names use event: (default is message).
Unique IDs use id:.
Two consecutive newlines terminate a complete event.
2. Built‑in reconnection and replay
When a network glitch occurs, the browser’s EventSource automatically retries the connection using an exponential‑backoff algorithm. The retry request includes the last received ID: Last-Event-ID: 102 The server can then resume streaming from the next ID, ensuring no data loss.
3. Minimal code on both client and server
Client side (plain JavaScript):
// Establish SSE connection
const evtSource = new EventSource("/api/market-stream");
// Default message handler
evtSource.onmessage = (event) => {
console.log("Default data:", event.data);
};
// Custom event handler for "trade"
evtSource.addEventListener("trade", (event) => {
const payload = JSON.parse(event.data);
console.log("Trade update:", payload.symbol, payload.price);
});
// Error handling (reconnection is automatic)
evtSource.onerror = (err) => {
console.error("Connection error, browser reconnecting...", err);
};Server side (Python FastAPI example):
import asyncio
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def event_generator():
event_id = 100
while True:
await asyncio.sleep(1)
event_id += 1
yield f"id: {event_id}
event: trade
data: {{\"symbol\": \"BTCUSDT\", \"price\": 65000}}
"
@app.get("/api/market-stream")
async def market_stream():
return StreamingResponse(
event_generator(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
)Architecture Selection Guide
Choosing between SSE and WebSocket depends on the communication pattern:
When to pick SSE (server‑to‑client only)
LLM token streaming – the client sends a single request and receives a continuous token stream.
Real‑time market or sports data – frequent updates that are read‑only on the client.
System status notifications and long‑task progress bars – e.g., order status changes, build or video‑transcode progress.
Key advantages of SSE for these scenarios:
Minimal protocol, low ops and debugging cost.
Works seamlessly with Nginx, Cloudflare CDN, and enterprise gateways.
Benefits from HTTP/2 or HTTP/3 multiplexing, avoiding TCP connection explosion.
Native automatic reconnection and data replay.
When to pick WebSocket (high‑frequency bidirectional)
Real‑time multiplayer games – frequent position sync and collision detection.
Instant messaging and collaborative editing – clients need to send messages as fast as they receive them.
High‑throughput binary streams – live audio/video or compressed binary payloads.
Conclusion
The evolution of real‑time web communication is not about using the most complex tool, but about matching the tool to the problem. While many engineers default to WebSocket, the rise of generative AI and unidirectional streaming makes SSE a lightweight, network‑friendly, and cost‑effective solution for most one‑way data push use cases.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
