Library
10 min read

WebSockets vs SSE vs long polling

Published

HTTP was designed for the browser to ask and the server to answer. But a lot of products need the server to speak first: a new WhatsApp Web message, a wicket in the IPL final, a Swiggy order that just left the restaurant, a stock price tick. There are four ways to do it, and they trade simplicity against cost and against which direction data needs to flow.

Your answer

During an India vs Pakistan match, 50 million people have a live score page open. The score changes about once every 30 seconds, and nobody sends anything back. Would you hold 50 million WebSocket connections? What else could work?

The four options#

Short polling is a timer. It is trivially simple, works through every proxy and caches well, but most requests return nothing and updates arrive late by up to one interval.

Long polling is a polite trick on plain HTTP: the server holds the request until it has something to say. Near real time, works everywhere, but every message costs a new request, and you must handle the gap between one response and the next request.

Server sent events (SSE) keep one HTTP response open and stream text events down it. The browser's EventSource handles parsing and reconnects automatically, resuming from the last event id. It only goes from server to client, which is all a score feed, a notification bell or a token by token AI answer needs. (ChatGPT style streaming responses use exactly this format.)

WebSockets upgrade an HTTP connection into a full duplex channel. Either side sends messages at any time with tiny overhead. They are the right tool when the client talks a lot too: chat, multiplayer games, collaborative editors, trading screens. You get no automatic reconnection, no resume and no HTTP caching or semantics; you build those yourself or use a library like Socket.IO.

ts
const events = new EventSource('/matches/ind-pak/stream')
events.onmessage = (e) => render(JSON.parse(e.data))
// Dropped connection? EventSource reconnects by itself and sends Last-Event-ID.

What it costs at scale#

Persistent connections are cheap per message and expensive to hold. Each open connection costs memory on the server (kernel buffers plus your application's per connection state), a file descriptor, and a slot on the load balancer. Polling holds nothing but repeats work.

50 million fans watching a match
50 million
10 KB
5 s
Memory for SSE or WebSocket connections50M x 10 KB = 500 GB
Servers at about 500K connections each100
Polling requests per second instead50M / 5 s = 10.0 M/s
10.0M req/s
of polling, every one answerable from a CDN cache with a 2 s TTL

Both are big numbers. The difference: a CDN can absorb millions of identical cached GETs a second at the edge, while every open connection needs your own servers. For a read only score that changes every 30 seconds, cached polling is the boring answer that works. Push only the users who need sub second updates.

Persistent connections also change how you scale and deploy. Connections are sticky: a user's messages arrive on whichever server holds their connection, so servers need a pub/sub backplane (Redis pub/sub, NATS, Kafka) to deliver a message to a user connected elsewhere. A deploy has to drain connections gently or a million clients reconnect at the same moment and hammer your auth service, the thundering herd. Add jitter to reconnect delays.

ChoiceWhat you gainWhat you payPick it when
Short pollingSimplest, stateless, cacheable at a CDN, works through anything.Wasted requests, latency up to one interval.Updates every few seconds or slower, huge read only audiences, dashboards.
Long pollingNear real time over plain HTTP, works with old proxies.A request per message, gaps between requests, holds server resources.A fallback when SSE and WebSockets are blocked. Rarely the first choice now.
Server sent eventsPlain HTTP, auto reconnect with resume, works with HTTP/2 multiplexing and normal auth.Server to client only, text only. Six connection limit per domain on HTTP/1.1.Feeds, notifications, live scores, progress, streaming LLM output.
WebSocketFull duplex, low overhead per message, binary support.Stateful, sticky, no built in reconnect or resume, some proxies interfere.Chat, games, collaborative editing, anything chatty in both directions.
Names you will hear
  • Socket.IOWebSocket library with fallbacks and rooms
  • RedisPub/sub backplane between connection servers
  • CloudflareDurable Objects, edge WebSockets
  • AWSAPI Gateway WebSocket APIs, AppSync subscriptions

In the interview#

Interviewer
For a chat app like WhatsApp Web, how do messages reach the browser?
Two way, low latency, many messages: the WebSocket case. The follow up is about scale.
You
A WebSocket per client to a fleet of connection servers. Each server keeps a map of user to socket and registers in a presence store which server holds which user. When a message for Ravi arrives, the chat service looks up his server and publishes to it through a pub/sub layer. Messages are also written to storage first, so if Ravi is offline or reconnecting he fetches what he missed by last seen message id. The socket is a delivery shortcut, not the source of truth.
The last sentence is the senior point: the connection can drop at any time.
Interviewer
And for the live cricket score?
You
Read only and changes every few seconds, so I would not hold 50 million sockets. Clients poll a small JSON file every few seconds and the CDN serves it with a one or two second TTL, so origin traffic is tiny. If we need ball by ball within a second for some users, SSE from edge servers fed by pub/sub.
Which would you pick?
A notification bell that lights up when someone comments
A Google Docs style editor with live cursors
A CI dashboard that refreshes build status
Streaming an LLM's answer token by token
A corporate network that strips Upgrade headers

Checkpoint#

Checkpoint

1. Which option reconnects and resumes from the last event automatically?

2. Why might short polling beat WebSockets for a huge read only audience?

3. A user connected to server A must receive a message produced on server B. What is needed?

Worth memorising
  • Short poll: timer. Long poll: held request. SSE: one way stream. WebSocket: two way channel.
  • SSE auto reconnects and resumes with Last-Event-ID. WebSockets do not.
  • Persistent connections need a pub/sub backplane and careful deploys.
  • Huge read only audiences: CDN cached polling is often the right answer.
  • The socket is a delivery shortcut. Storage is the source of truth.
Say this in 60 seconds

There are four ways to push updates to a browser. Short polling asks on a timer; it is simple and cacheable but wasteful and late by up to one interval. Long polling holds each request until there is news, giving near real time over plain HTTP at the cost of a request per message. Server sent events keep one HTTP response open and stream events from server to client, with automatic reconnect and resume via Last-Event-ID, which suits feeds, notifications, scores and streaming LLM output. WebSockets upgrade to a full duplex channel with tiny per message overhead, right for chat, games and collaborative editing, but you build reconnection yourself. Persistent connections cost memory per connection, need a pub/sub backplane to reach users on other servers, and need careful draining on deploy. For a huge read only audience like a live score, I would poll a CDN cached endpoint, and keep messages in storage so the connection is never the source of truth.