Skip to content
System design course
Ch.2 · The building blocks·concept ·8 min read

Real-time delivery — polling, long-polling, WebSockets, SSE

Four ways to get fresh data from server to client, from crude polling to full-duplex sockets — and how to pick for chat, feeds, and dashboards.


The core problem

HTTP is request–response: the client asks, the server answers. But many features need the server to push fresh data — a new chat message, a live score, a notification. These four techniques bridge that gap, trading simplicity for immediacy and efficiency.

Short polling

The client asks “anything new?” on a fixed timer (every few seconds). Simple and works everywhere, but wasteful: most requests return nothing, and updates lag by up to one interval. Fine for low-frequency, non-urgent data; bad at scale.

Long polling

The client makes a request and the server holds it open until it has data (or a timeout), then responds; the client immediately re-requests. Updates arrive near-instantly with far fewer empty responses than short polling. Costs: many held-open connections, and it’s still one message per round trip (no true server push stream). A solid, broadly-compatible choice.

WebSockets

A single TCP connection, upgraded from HTTP, that stays open for full-duplex (both directions, anytime) messaging. The server can push the instant something happens, and the client can send just as freely — low overhead per message.

  • Best for: chat, multiplayer, collaborative editing, live trading — anything bidirectional and high-frequency.
  • Costs: stateful long-lived connections (harder to load-balance and scale — you need sticky routing or a pub/sub backplane), and they need fallbacks where sockets are blocked.

Server-Sent Events (SSE)

A long-lived HTTP connection over which the server streams events to the client — but one-directional (server → client only). Lighter than WebSockets, runs over plain HTTP, and auto-reconnects.

  • Best for: live feeds, notifications, dashboards, progress updates — push where the client doesn’t need to stream back.
  • Costs: server→client only; limited by browsers’ per-domain connection caps (mostly a non-issue over HTTP/2).

Choosing

NeedReach for
Occasional, non-urgent updatesShort polling
Near-real-time, broad compatibilityLong polling
Two-way, high-frequencyWebSockets
One-way server push, simpleSSE

The decision rule: does the client need to push too? Yes → WebSockets. No, just receive a stream → SSE. Need it dead simple or maximally compatible → long polling. (These reappear as a sharper trade-off, with webhooks added for server-to-server, in Chapter 3.)

The scaling footnote

All persistent-connection approaches (long poll, WebSockets, SSE) hold state per client on the server, so a million concurrent users means a million open connections. That’s why real-time systems put a pub/sub layer behind the connection servers: connection nodes stay dumb and stateless-ish, subscribing to channels, while a message broker fans events out to them.