Part I β The Pipes Β· Lesson 2.5
Server Side Events
In one lineA one-way stream over ordinary HTTP that reconnects and resumes by itself.
Where you've seen itA live cricket score ticker. Thousands of viewers, no one sending anything back β exactly the shape SSE is for.
Diagram
ONE REQUEST, MANY RESPONSES
Client Server
βββ GET /scores ββββββββββββββΊβ Accept: text/event-stream
βββ 200, Content-Type: text/event-stream
β β (response never ends)
βββββ event 1 βββββββββββββββββ
βββββ event 2 βββββββββββββββββ
βββββ event 3 βββββββββββββββββ
β β network drops β
βββ GET /scores ββββββββββββββΊβ browser retries automatically
β Last-Event-ID: 3 β β sent for you, no code
βββββ event 4 βββββββββββββββββ server resumes from 3THE WIRE FORMAT β plain text, newline delimited
id: 42
event: score
data: {"runs":186,"wickets":4}
β β blank line ends the event
retry: 5000 β server sets the reconnect delaySSE vs WEBSOCKET β same latency, different bill
SSE WebSocket
direction server β client only both ways
protocol plain HTTP (cacheable custom framing after
infra, proxies, HTTP/2) the upgrade
reconnect built into the browser you write it
resume Last-Event-ID, free you write it
binary no (text only) yesHow it works
- Client opens
new EventSource('/scores')β a normalGETthat stays open. - Server streams text events, each ending in a blank line, and never closes the response.
- Every event carries an
id:; the browser remembers the last one seen. - On a drop, the browser reconnects on its own and sends
Last-Event-IDβ the server replays from there. - Client listens per event type:
es.addEventListener('score', β¦).
const es = new EventSource('/scores');
es.addEventListener('score', (e) => render(JSON.parse(e.data)));
es.onerror = () => {/* browser is already retrying β don't reconnect here */};Trade-offs
| Use when | Avoid when |
|---|---|
| Only the server has news | The client must send too β WebSocket |
| Feeds, tickers, notifications, logs | You need binary frames |
| You want reconnect + resume for free | Many streams per tab on HTTP/1.1 |
| Streaming LLM tokens to the UI | β |
The HTTP/1.1 six-connection limit: each EventSource occupies one of the browser's six connections per origin, and an open stream never frees it. Over HTTP/2 the limit effectively disappears β this alone is a reason to be on HTTP/2 before shipping SSE.
Interview angle
"Score ticker for ten million viewers β SSE or WebSocket?"
- SSE: the client never sends anything, so duplex is wasted capacity and wasted code.
- Reconnect and replay come free via
Last-Event-ID, which is the hard part of a WebSocket build. - It's plain HTTP, so it rides existing CDN, proxy, and HTTP/2 infrastructure β but confirm HTTP/2 first.
Recap
- One-way, text-only, plain HTTP, streamed over a response that never ends.
- Auto-reconnect and
Last-Event-IDresume are the killer features. - Default to SSE for feeds; upgrade to WebSocket only when the client must talk back.