WebSockets vs Server-Sent Events vs polling — which transport when?
Polling is simplest (HTTP). SSE is one-way server→client (text, auto-reconnect, HTTP/2-friendly). WebSockets are bidirectional, binary-capable, lowest-latency. Pick the *least* powerful that fits — operational cost rises with each.
Three transports for "the server has new data":
Polling — client sends GET /events every N seconds. Pros: trivial, works through every proxy, idempotent. Cons: latency (worst case = N seconds), wasted requests, hard to scale below ~5s.
Long polling — server holds the request open until data arrives, then returns. Latency is near-instant. Cons: complex to operate at scale, proxy timeouts, one connection per client.
Server-Sent Events (SSE) — server streams text events over an HTTP response. Pros: native EventSource API, automatic reconnect with Last-Event-ID, plays nicely with HTTP/2 multiplexing, simple to debug. Cons: one-way (server → client only), text only, no IE.
WebSockets — full-duplex, binary-capable. Pros: lowest latency in both directions, low overhead per message. Cons: requires upgrade negotiation, separate scaling/load-balancing concerns, more error states (connection drops, message ordering on reconnect), often need a separate sticky-session infra.
Decision flow:
- Need to send messages to the server in real time? → WebSocket.
- One-way push from server is enough? → SSE.
- Updates are infrequent (≥30s) or you can't operate stateful infra? → Polling.
Modern alternatives often used: WebTransport (HTTP/3), GraphQL subscriptions over WebSocket, libraries like Pusher/Ably/Liveblocks that abstract the transport.
Code
Follow-up questions
- •How do you scale WebSockets across multiple servers?
- •When does HTTP/2 multiplexing remove SSE's connection-limit problem?
- •How do you handle ordering and dedupe across reconnects?
Common mistakes
- •Defaulting to WebSockets for read-only updates that SSE handles cheaper.
- •Not handling reconnect / backoff — temporary network blips kill the stream forever.
- •Forgetting to authenticate the upgrade — an unauthenticated WS endpoint is a foot-gun.
Performance considerations
- •Connection counts: polling = N clients × 1 short request per cycle. WebSocket = N persistent connections — server memory and load-balancer config matter.
Edge cases
- •Corporate proxies sometimes break WebSocket upgrades but allow SSE.
- •Browsers cap concurrent SSE connections per origin (~6 over HTTP/1) — HTTP/2 fixes this.
Real-world examples
- •Stripe Dashboard uses SSE for activity feeds; Figma and Linear use WebSockets for collaborative editing.