Back to Archives
Architecture12 min read

System Design: Scaling WebSockets using Redis Pub/Sub Backplanes

Published on May 18, 2026 by Amrit Sharma

WebSockets establish persistent TCP connections between clients and servers. This works beautifully for single-instance applications but breaks down completely when scaling horizontally behind a round-robin load balancer. If Client A is connected to Instance 1, and Client B is connected to Instance 2, they cannot communicate directly without a coordination layer.

1. The Horizontal Scaling Dilemma

Unlike stateless REST endpoints, WebSocket servers hold stateful memory connections. If a message needs to be broadcast to all connections, Instance 1 can only write packets to sockets inside its own execution thread, leaving clients on Instance 2 completely unaware of the event.

2. Redis Pub/Sub as the Backplane

We can solve this scaling bottleneck by establishing a Redis Pub/Sub coordinator backplane. When an instance receives a broadcast instruction, it publishes it to a Redis channel, and all sibling nodes subscribing to that channel receive the payload and broadcast it locally.

const redis = require("redis");
const io = require("socket.io")(server);

const pubClient = redis.createClient({ url: "redis://localhost:6379" });
const subClient = pubClient.duplicate();

Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  io.adapter(createAdapter(pubClient, subClient));
  console.log("WebSocket Redis adapter connected.");
});