Real-Time: Polling, Long Polling, WebSockets and SSE
Four ways for a server to tell a client that something happened: polling, long polling, Server-Sent Events and WebSockets. How each works, what it costs, and how to scale millions of open connections.
In a nutshell
- Polling: ask every few seconds. Simple, but wasteful and slow to notice changes.
- Long polling: ask, and the server holds the request until there is news. Works everywhere.
- SSE: one long HTTP response the server keeps writing to. Server → client only, auto-reconnects.
- WebSockets: a full two-way connection. Best for chat, games and collaboration; harder to scale.
The problem
Plain HTTP is client-initiated: the server can only answer questions. But chat messages, live scores, notifications and collaborative editing need the server to tell the client as soon as something happens. There are four common ways to do it.
Polling
Short polling
Diagram as text
- Client → Server: anything new?
- Server → Client: no
- Client → Server: anything new? (5 s later)
- Server → Client: no
- Client → Server: anything new? (5 s later)
- Server → Client: yes: 1 message
Easy to build and fine for slow-changing data (a dashboard refreshing every minute). But it wastes requests when nothing changes, and updates arrive up to one interval late. A million users polling every 5 seconds is 200,000 requests per second, mostly for nothing.
Long polling
Long polling
All steps The server holds the request open until there is news (or a timeout), then the client immediately asks again.
- The client sends a request, and the server does not answer straight away.
- The server waits until there is something to send, or until a timeout of perhaps 30 seconds.
- As soon as a message arrives, the server answers.
- The client immediately sends the next request, so there is almost always one waiting.
Diagram as text
- The client sends a request, and the server does not answer straight away.
- The server waits until there is something to send, or until a timeout of perhaps 30 seconds.
- As soon as a message arrives, the server answers.
- The client immediately sends the next request, so there is almost always one waiting.
Updates arrive almost instantly, and it is plain HTTP, so it works through proxies and firewalls. The cost: a held request per user on the server, and a new request after every message.
Server-Sent Events (SSE)
With SSE, the client opens one HTTP request and the server never finishes the response: it keeps writing events down it as they happen. Browsers support it natively with the EventSource API, which reconnects automatically and resumes from the last event ID.
Server-Sent Events
Diagram as text
- Browser → Server: GET /events (Accept: text/event-stream)
- Server → Browser: event: score 1–0
- Server → Browser: event: score 1–1
- Server → Browser: event: score 2–1
Perfect for one-way feeds: live scores, notifications, progress bars, and streaming text from AI models. It is simple HTTP, so it works with existing load balancers and authentication. The client still sends its own messages with normal requests.
WebSockets
A WebSocket starts as an HTTP request that asks to upgrade the connection. Once the server agrees, the same TCP connection becomes a two-way channel: both sides can send messages at any time, with tiny framing overhead.
WebSocket
All steps After the upgrade, both sides talk freely over one long-lived connection.
- The client sends an HTTP request asking to upgrade to the WebSocket protocol.
- The server agrees. From now on this is no longer HTTP request/response.
- The client sends messages whenever it likes.
- The server pushes messages whenever it likes, without being asked.
- Small, frequent events such as typing indicators are cheap to send.
Diagram as text
- The client sends an HTTP request asking to upgrade to the WebSocket protocol.
- The server agrees. From now on this is no longer HTTP request/response.
- The client sends messages whenever it likes.
- The server pushes messages whenever it likes, without being asked.
- Small, frequent events such as typing indicators are cheap to send.
Ideal for chat, multiplayer games, collaborative editors and trading screens. The cost is in operations: connections are long-lived and stateful, so scaling and deployments need more care.
Comparing them
| Polling | Long polling | SSE | WebSockets | |
|---|---|---|---|---|
| Direction | Client asks | Client asks, server waits | Server → client | Both ways |
| Delay | Up to one interval | Near instant | Instant | Instant |
| Overhead | High (many empty requests) | Medium | Low | Lowest per message |
| Works through any proxy | Yes | Yes | Usually | Usually; some proxies need configuration |
| Good for | Slow-changing data | Fallback, simple notifications | Feeds, notifications, streaming output | Chat, games, collaboration |
Scaling open connections
A million online users means a million open connections spread over many servers. When user A sends a message to user B, B may be connected to a different server. The usual solution is a pub/sub layer between connection servers:
Fan-out across connection servers
Diagram as text
- User A → Socket server 1: send
- Socket server 1 → Pub/sub: publish
- Pub/sub → Socket server 2: deliver
- Socket server 2 → User B: push
- Keep connection servers thin: they hold sockets and relay messages; business logic lives in normal services.
- Use a pub/sub system (for example Redis Pub/Sub, or a streaming platform) to route messages between servers.
- Plan for reconnects: deployments and network changes drop connections, so clients reconnect with backoff and catch up on missed messages.
- Load balancers must support long-lived connections and not cut them on short idle timeouts.
Common mistakes
- Using WebSockets for a feed that only flows server → client, where SSE would be simpler.
- Polling every second from millions of clients and then scaling servers to answer "no".
- Ignoring reconnects: no backoff, so a deployment triggers a thundering herd of reconnections.
- Keeping per-user state only in one socket server's memory, so messages are lost when it restarts.
Interview questions
Try answering out loud before you open each one.
How would you push notifications to a web app?
If messages only flow server to client, Server-Sent Events: simple HTTP, native browser support and automatic reconnects. If the client also sends frequent messages (chat), WebSockets. Long polling as a fallback where neither works. Behind the connection servers, a pub/sub layer delivers each event to whichever server holds the user's connection.
How do you scale a chat system to millions of concurrent users?
Run many stateless-ish connection servers behind load balancers that support long-lived connections. Track which server each user is connected to (or use pub/sub channels per user or room), publish messages once and let subscribed servers push them. Store messages durably so reconnecting clients can catch up, and add backoff with jitter for reconnects.
Check yourself
Related topics
Further reading
- Using server-sent events MDN Web Docs
- RFC 6455: The WebSocket Protocol IETF, 2011
Your notes
Saved in this browser as you type.
Finished this topic?
Mark it read to track your progress, then carry on with the next one.