Skip to content
fearchitect
State & Data

Real-time: WebSockets vs SSE vs Polling

Match the right real-time transport to your data-flow direction.

By Abas TurabliReviewed

Summary

Polling, Server-Sent Events, and WebSockets each trade connection state, directionality, and infrastructure cost differently. Short polling is the simplest fallback; SSE is HTTP-native one-way push; WebSockets give full-duplex at the cost of stateful servers and trickier load-balancing.

Jump to the interview angle

Transport comparison

TransportDirectionReconnectProtocolBest fit
Short pollingClient → Server (request-driven)None — new request each tickPlain HTTP GET on timerAny proxy, any CDN
Long pollingClient → Server (request-driven)New request on responsePlain HTTP, server blocksLow-latency fallback when SSE blocked
SSE (EventSource)Server → Client onlyAutomatic + Last-Event-ID replayHTTP/1.1 text/event-streamNotifications, feeds, live dashboards
WebSocketFull-duplex (both directions)Manual — you write backoff logicHTTP 101 upgrade → WS framesChat, games, collaborative editing

SSE with controlled backoff

Close EventSource on error and schedule reconnect manually so backoff delay stays predictable — the browser's built-in retry uses a fixed 3 s.

SSE with EventSource and exponential-backoff reconnectts
// Works in any browser; replace URL with your endpoint.
function connectSSE(url: string, onMessage: (data: string) => void) {
  let es: EventSource;
  let retryDelay = 1_000; // ms

  function connect() {
    es = new EventSource(url, { withCredentials: true });

    es.addEventListener("message", (e) => {
      retryDelay = 1_000; // reset on success
      onMessage(e.data);
    });

    es.addEventListener("error", () => {
      es.close();
      // EventSource would auto-reconnect, but we want backoff control
      setTimeout(connect, retryDelay);
      retryDelay = Math.min(retryDelay * 2, 30_000);
    });
  }

  connect();
  return () => es.close(); // cleanup
}

// Server side (Node / Edge):
// res.setHeader("Content-Type", "text/event-stream");
// res.setHeader("Cache-Control", "no-cache");
// res.write(`data: ${JSON.stringify(payload)}\n\n`);

Closing EventSource on error bypasses the browser's fixed 3 s retry; backoff doubles up to 30 s, preventing server floods.

Polling opens a new connection per tick; SSE streams over one long HTTP response; WebSocket upgrades to a full-duplex channel.

Pick by directionality first

One-way server push → SSE. Both sides send → WebSocket. No persistent connection acceptable, or behind proxies that block upgrades → polling.

Interview angle

Lead with directionality, then connection cost, then infra constraints. Mention SSE is often overlooked despite being simpler than WebSockets for one-way push.

Soundbite: "SSE for one-way push behind HTTP; WebSocket when the client sends too."

Key terms

EventSource
Browser API for SSE: opens a persistent GET, fires `message` events, auto-reconnects with `Last-Event-ID`.
WebSocket upgrade
HTTP 101 handshake that switches a TCP connection to the WebSocket frame protocol.
Long polling
Server holds a request open until data is ready, reducing empty responses vs. fixed-interval polling.
Sticky session
Load-balancer rule routing one client to the same server node, needed for stateful WebSocket connections.
Heartbeat / ping-pong
Periodic frames sent to keep a TCP connection alive through idle-timeout proxies.

Further reading

Search fearchitect

Jump to a topic, mode, or action.