awesome-everything RU
↑ Back to the climb

Networking & Protocols

WebSocket vs SSE vs long-polling: choosing the right transport

Crux Latency, overhead, and proxy compatibility compared across WebSocket, Server-Sent Events, and long-polling — so you pick the right tool before you build.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 10 min

Before you reach for WebSocket, ask whether you actually need bidirectional communication. SSE handles 90% of “server needs to push” use cases with zero custom reconnection logic and friendlier proxies. Picking the wrong transport costs you weeks of debugging or unnecessary complexity.

Three transports, three models

WebSocketSSELong-polling
DirectionBidirectionalServer→client onlyServer→client (client polls)
ProtocolBinary frame (RFC 6455)text/event-stream over HTTPPlain HTTP
Overhead2–6 bytes per frame~5 bytes + metadata per event~500+ bytes headers per request
Latency0–5 ms3–8 msPoll interval + RTT (100–60000 ms)
ReconnectApplication must implementBrowser EventSource handles itApplication re-opens request
Proxy supportRequires Upgrade supportWorks with any HTTP proxyWorks everywhere

WebSocket — full-duplex, minimal overhead

After the upgrade handshake, either side sends frames at any time. Per-message overhead is 2–6 bytes. The server can push without the client asking; the client can push without a new HTTP connection. This is the right choice when:

  • The client sends data frequently (game input, collaborative editing, trading orders).
  • Latency budget is under 10 ms.
  • You control the proxy/infrastructure (or know it supports Upgrade).

Downside: no built-in reconnection. If the connection drops (proxy idle timeout, network glitch), your code must detect close code 1006 and reconnect with backoff.

SSE — server push, browser handles everything

SSE uses a normal persistent HTTP response with Content-Type: text/event-stream. The server writes newline-delimited events:

event: price-update
data: {"symbol":"AAPL","price":182.34}
id: 4291

The browser’s native EventSource API parses events and automatically reconnects using the Last-Event-ID header if the connection drops. Latency is 3–8 ms. Zero reconnection code to write. Works through any HTTP/1.1 proxy including corporate firewalls.

SSE is wrong when:

  • The client needs to send data (you need a separate REST endpoint for that, which is awkward).
  • You need binary payloads (SSE is text-only).

Long-polling — the universal fallback

The client opens an HTTP request and the server holds it open until data arrives (or a timeout fires). When the server responds, the client immediately opens a new request. This simulates server push using only standard HTTP.

Latency = the time the server holds the request + one RTT. At best, 100 ms for a server that answers immediately. At worst, 60+ seconds for a server with a long timeout before giving up and responding empty.

Overhead is high: every poll carries full HTTP headers (~500+ bytes). At 50,000 clients polling every 100 ms, that is 500,000 HTTP requests/second. Essentially no modern application uses long-polling as a primary transport — it is the graceful fallback for environments that block WebSocket.

Transport latency and overhead comparison
WebSocket frame header (server→client)
2 bytes
WebSocket message latency after handshake
0–5 ms
SSE event overhead (minimum)
~5 bytes + metadata
SSE message latency
3–8 ms
Long-poll HTTP headers per request
~500+ bytes
Long-poll effective latency (best case)
100–500 ms

Subprotocol and extension negotiation

The client can request an application-layer subprotocol during the upgrade:

Sec-WebSocket-Protocol: chat, superchat

The server picks one and echoes it back. Subprotocols let teams version their message format without touching the WebSocket layer — chat uses JSON messages, superchat uses a compact binary format. If the server sends no subprotocol header, the connection has no named protocol (still valid; the application defines the message format implicitly).

Extensions work similarly via Sec-WebSocket-Extensions. The most important extension in practice is permessage-deflate (RFC 7692): DEFLATE compression per message. On text payloads (JSON, HTML) compression ratios of 50–90% are typical. On small messages (< 64 bytes) compression can expand the payload. On already-compressed data (images, video) it achieves nothing. The memory cost is significant: at default settings, each compressor consumes ~256 KB and each decompressor ~44 KB — at 100k idle connections, that is ~25 GB of RAM from compression state alone. Most production deployments disable permessage-deflate by default.

Why this works

Why SSE is underused. SSE was standardised in HTML5 in 2009 but was largely ignored because WebSocket launched at the same time and was more exciting. In practice, SSE covers most notification, feed, and dashboard use cases cleanly: server pushes events, browser reconnects automatically, no special proxy configuration needed. The cases that truly require WebSocket are those where the client sends data at high frequency — games, collaborative editors, trading terminals.

Quiz

A company has 1,000 WebSocket connections. The old approach opens 1,000 TCP connections to the backend, each consuming ~10 KB of memory at idle. Moving to HTTP/2 extended CONNECT (RFC 8441), the client multiplexes all WebSocket connections over one TCP connection consuming 50 KB total. What is the approximate memory saving?

Pick the best fit

A notification system pushes ~5 updates per minute to 100k users. Users never send data to the server. Which transport?

Recall before you leave
  1. 01
    Name two use cases where SSE is a better choice than WebSocket, and explain why.
  2. 02
    Why does permessage-deflate consume so much memory at scale, and what is the production mitigation?
  3. 03
    A browser sends data to the server every 50 ms (e.g., mouse positions for a collaborative editor). Why is SSE insufficient here, and what is the correct transport?
Recap

Three transports solve the “server needs to push” problem at different trade-offs. WebSocket offers the lowest latency (0–5 ms) and true bidirectionality — the right choice when clients send data frequently. SSE streams text/event-stream over a persistent HTTP connection, with the browser’s EventSource handling reconnection via Last-Event-ID automatically — the right choice for server-push-only use cases in proxy-heavy environments. Long-polling simulates push over plain HTTP at 500+ bytes of header overhead per poll and ~100–500 ms effective latency — it is the universal fallback, not a primary transport. WebSocket subprotocols let teams version their message schema; the permessage-deflate extension adds 50–90% text compression but costs ~256 KB RAM per connection compressor context.

Connected lessons
appears again in162
Continue the climb ↑WebSocket backpressure: when clients can''''t keep up
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.