Skip to content
matthewcm.dev

    ↑ ↓ move · ↵ open · tab scopeopen graph →

    WebSockets

    A persistent, two-way channel between browser and server. Brilliant when both sides talk often; the price is stateful connections you now have to scale, heartbeat and reconnect.

    Evergreentended planted 2 min read
    On this page

    A WebSocket is a full-duplex channel over a single TCP connection. Once it’s open, either side can send a message at any time — no request needed. That’s what makes chat, multiplayer games, collaborative editors and trading screens feel live.

    How it starts

    A WebSocket begins life as an ordinary HTTP request with an Upgrade: websocket header. If the server agrees, it replies 101 Switching Protocols, and from then on the connection carries framed messages in both directions instead of request/response pairs.

    const ws = new WebSocket("wss://example.com/prices");
    ws.onopen = () => ws.send(JSON.stringify({ subscribe: ["BTC-USD"] }));
    ws.onmessage = (e) => handle(JSON.parse(e.data));

    When to use it (and when not)

    NeedReach for
    Both sides send frequently (chat, collaboration, games, order entry)WebSockets
    Only the server pushes (feeds, notifications, progress, LLM token streams)Server-Sent Events (SSEs) — simpler, plain HTTP
    Updates are rare or freshness isn’t criticalAJAX Polling
    Long-lived connections are blockedHTTP Long Polling

    The costs nobody mentions in the tutorial

    • Stateful connections. Each server holds its own sockets, so a message for a user has to reach whichever server they’re connected to. The usual fix is a pub/sub backplane (Redis, NATS, Kafka) plus a registry of who’s connected where.
    • Load balancers need WebSocket support and generous idle timeouts.
    • Dead peers look alive. Use ping/pong frames as a Heartbeat to detect them and to keep proxies from culling the connection.
    • Reconnection is your job. Exponential backoff with jitter, resubscribe, then replay anything missed using a sequence number. Without jitter, a deploy that drops every connection turns into a reconnect storm.
    • Deploys drop connections. Drain gracefully. The network topology does change — one of the Fallacies of Distributed Computing.
    • Security. Authenticate during the handshake, check the Origin header, and rate-limit messages.

    The frontend half

    Receiving messages is easy; rendering them is where real-time UIs fall over. If every message calls setState high in a React tree, the whole subtree re-renders many times a second. Own the socket in one place, write messages into a store, and let only the leaf components subscribe — the pattern in Zustand Transient Updates.

    In practice

    On real-time trading interfaces the lesson was that the socket is rarely the bottleneck; what you do per message is. Batch updates to the frame, drop intermediate values nobody can see, and measure render cost alongside network latency. Underneath, it’s still Message Passing: independent parties exchanging messages instead of sharing state.

    • #websockets
    • #real-time
    • #networking
    • #streaming

    ↪ Links to (7)