Home
About
Blog
Skills
Projects
Contact
Home
About
Blog
Skills
Projects
Contact
Back to Matrix
Web Dev 7/10/2026 6 min read

Building Real-Time Apps with WebSockets

Building Real-Time Apps with WebSockets
#WebSockets#Node.js#Real-time

Polling every two seconds means a thousand users generate half a million requests an hour, most returning nothing new. WebSockets replace that with one persistent, bidirectional TCP connection per client, upgraded from an ordinary HTTP request.

When You Actually Need Them

WebSockets are the right answer when data flows both ways and latency matters: chat, collaborative editing, multiplayer state, trading dashboards, live cursors. If updates only travel server to client, Server-Sent Events are simpler, survive proxies better, and reconnect automatically. If updates are rare, polling is genuinely fine. Choose the boring option when it fits.

The Two Things Every Implementation Forgets

Heartbeats. TCP will happily keep a dead connection open for minutes. Without application-level pings you serve a UI that looks connected and receives nothing.

Reconnection with backoff and jitter. When a server restarts, every client reconnects at once. Without jitter you have built a self-inflicted denial of service against your own infrastructure.

```js
function connect(url, onMessage) {
  let attempt = 0;
  let socket;

const open = () => { socket = new WebSocket(url);

socket.onopen = () => { attempt = 0; heartbeat(); }; socket.onmessage = (e) => onMessage(JSON.parse(e.data)); socket.onclose = () => { const delay = Math.min(30000, 500 * 2 attempt++); setTimeout(open, delay + Math.random() * 1000); }; };

const heartbeat = () => { if (socket.readyState !== WebSocket.OPEN) return; socket.send(JSON.stringify({ type: 'ping' })); setTimeout(heartbeat, 25000); };

open(); return () => socket.close(); } ```

Authentication and Authorisation

The upgrade handshake is your only reliable checkpoint, and browsers will not let you set custom headers on it. Pass a short-lived ticket as a query parameter or rely on a cookie, verify it before accepting the upgrade, and store the resulting identity on the connection. Then authorise every inbound message against that identity, because a client can send anything once the socket is open. Never trust a user id that arrives in the message body.

Scaling Beyond One Server

WebSocket connections are stateful, which breaks the assumptions of stateless load balancing. Two rules cover most of it.

  • Enable sticky sessions so a client's long-lived connection stays on the node that holds its state.
  • Broadcast through a pub/sub layer. A message published on node A must reach subscribers on node B, which is exactly what a Redis adapter or a dedicated message bus provides.
  • Cap connections per node and load test to find the real ceiling. Memory per idle connection is small but never zero.

Operational Details That Bite

Set idle timeouts on proxies above your heartbeat interval, or infrastructure will silently kill healthy sockets. Apply per-connection rate limits, since one abusive client can flood your event loop. And send the smallest useful payload: a delta with an id and changed fields, not the full object graph on every tick.

Get heartbeats, backoff, and pub/sub right and real-time stops being the fragile part of your stack.

Enjoyed this article?

Share it with your network and join the conversation.