How SSE Works
One persistent connection, many events
Server-Sent Events (SSE) solve the long-polling problems with a simpler model: the client opens one connection, and the server pushes events through it whenever data is available. The connection stays open indefinitely.
Unlike long polling (where the connection closes after each event and the client reconnects), SSE keeps the same connection open. The server streams events as they happen.
The protocol
SSE uses a plain HTTP response with Content-Type: text/event-stream. The body is a stream of text events, each separated by double newlines:
data: {"type":"task_created","task":{"id":"task-5","title":"New task"}}
data: {"type":"task_moved","task":{"id":"task-3","listId":"list-done"}}
data: {"type":"task_deleted","taskId":"task-2"}
Each event is a data: line followed by a blank line. That is the entire protocol.
The browser API
Browsers have a built-in EventSource API for SSE:
// Client-side
const source = new EventSource("/boards/board-1/events");
source.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Event:", data.type, data);
updateUI(data);
};
source.onerror = () => {
console.log("Connection lost. Reconnecting...");
// EventSource reconnects automatically
}; Three lines to set up a real-time connection. The browser handles reconnection, buffering, and connection management.
Automatic reconnection
When the connection drops (network issue, server restart), EventSource reconnects automatically after a short delay (typically 3 seconds). The client does not need to implement reconnection logic — it is built into the browser.
The server can control the reconnection delay:
retry: 5000
data: {"type":"task_created","task":{"id":"task-5"}}
The retry: field tells the browser to wait 5 seconds before reconnecting (instead of the default 3).
SSE vs long polling
| Feature | Long polling | SSE |
|---|---|---|
| Connection | Closes after each event | Stays open |
| Reconnection | Client implements | Browser automatic |
| Multiple events | One per connection cycle | Many per connection |
| Protocol | Standard HTTP response | text/event-stream |
| Browser API | fetch (manual) | EventSource (built-in) |
| Direction | Server → client | Server → client |
SSE is simpler, more efficient, and has better browser support than long polling. Use long polling only as a fallback for environments that do not support SSE.
Exercises
Exercise 1: Open a terminal and send a raw SSE response with curl: curl -N http://localhost:3000/boards/board-1/events. (The endpoint does not exist yet — we build it in the next lesson.)
Exercise 2: In a browser console, create an EventSource connection to any endpoint that returns text/event-stream. Observe the onmessage callbacks.
Exercise 3: Read the MDN documentation on EventSource. What happens when the connection drops? (Answer: onerror fires, then the browser reconnects automatically after the retry interval.)
What is the key advantage of SSE over long polling?