Chat. Live scores. Notifications. Collaborative editing. Any feature where the server pushes data to the client the moment it's ready. HTTP was designed for the opposite: client asks, server answers. To make push happen, you pick one of three techniques: polling, Server-Sent Events (SSE), or WebSockets. Each has radically different resource costs, browser support, and failure modes.
"Use WebSockets" is the lazy answer. Often SSE is better. Sometimes plain polling is enough. Know which trade-off you're making.
02
The spectrum
Technique
Direction
Per-connection cost
Reconnect?
Best for
Short polling
Client → Server (repeat)
Full HTTP each time
N/A
Low-frequency updates (every minute+)
Long polling
Client → Server (held open)
Full HTTP, server holds up to 30s
Client retries on each response
Stepping-stone when WS/SSE unavailable
Server-Sent Events (SSE)
Server → Client only
One TCP connection, streams text lines
Auto-reconnect with Last-Event-ID
Feeds, notifications, live counters — anywhere push is one-way
WebSockets
Bidirectional
One TCP connection, binary or text frames
Manual
Chat, gaming, collaborative editing, anything where client also sends
03
SSE — the underappreciated one
An SSE endpoint is just an HTTP endpoint that never closes. Set Content-Type: text/event-stream, stream text events separated by blank lines. Browsers handle it via new EventSource(url).
Free auto-reconnect: if the connection drops, the browser reconnects and sends Last-Event-ID: 42 so the server resumes from where it left off. Works through firewalls that don't like WebSockets. Runs over HTTP/2 for multiplexing.
Use SSE when updates flow server → client. Most "real-time" features (news feed, dashboards, status pages) actually are one-way. WebSockets add complexity you don't need.
04
Deep dive — why WebSockets are harder than they look
A WebSocket is a long-lived TCP connection. That's great for latency, terrible for infrastructure:
Sticky connections. A user's WS lands on server 3. A new message for that user arriving at server 7 needs a pub/sub fabric (Redis, Kafka) so server 3 can pick it up.
No REST-style horizontal scaling. 1M concurrent users = 1M open sockets = your server fleet must hold state. Restarting a node drops thousands of connections.
Load balancers hate them. Most LBs have default idle timeouts of 60s; WS needs heartbeats (ping/pong frames) to stay alive. Forget to configure and users drop every minute.
TLS termination gets weird. Some proxies close idle WS after 5 minutes. Some strip WS upgrade headers. Always test your prod path end-to-end.
Reconnect logic is on you. Unlike SSE, WS has no built-in "last event ID." Your app resends the last-seen timestamp on reconnect and the server backfills.
Real WebSocket systems (WhatsApp, Discord, Slack) have specialized WS gateway fleets, pub/sub backbones, and careful connection-draining on deploy. It's an order of magnitude more infra work than SSE.
Heuristic
Need bidirectional? WebSockets. Push-only? SSE. Not sure? Start with long polling — cheapest to build, easiest to debug — and upgrade only when traffic justifies it.
05
Real-world
WhatsApp
Custom over TLS (not raw WS)
WhatsApp uses a custom XMPP-derived binary protocol over TLS, not WebSockets. 50M+ concurrent connections per fleet.
Discord / Slack
WebSockets with a gateway tier
Client connects to a gateway service that handles the WS lifecycle; business logic sits behind. Pub/sub for cross-server delivery.
Every keystroke needs bidirectional transmission (client sends ops, server distributes). WS is the right call.
06
Used in problems
WhatsApp (WebSockets + custom protocol). Notification system (WS for user clients + SSE for web dashboard). Video conferencing (signaling over WS, media over WebRTC/UDP). PUBG (UDP for game state; WS fallback). Stock trading (WS for live quotes).