Spring Fresh Sale! - Up To 67% OFF BDIX Hosting + Free Domain
Node.js

How to Scale WebSockets and Socket.IO Across Multiple Node.js Instances

Scaling WebSockets is trickier than scaling normal HTTP, because connections are long-lived and stateful — a message from one instance must reach clients connected to another. The solution has two parts: sticky sessions and a shared adapter. Here is how it works with Socket.IO.

Why WebSockets need special handling

A normal HTTP request is short and can go to any instance. A WebSocket stays open, tied to one instance. Run several instances and two problems appear: a client must keep talking to the same instance, and a broadcast on one instance must reach clients on the others.

Part 1: Sticky sessions

Configure your load balancer or reverse proxy to keep each client pinned to the same backend instance for the life of the connection. Without this, the WebSocket handshake can break as requests bounce between instances.

Part 2: A Redis adapter

To let instances share events, use Socket.IO's Redis adapter. It uses Redis publish/subscribe so that when one instance emits to a room, every instance delivers it to its own connected clients:

io.adapter(createAdapter(pubClient, subClient));

Now a broadcast reaches all clients, regardless of which instance they are on.

Proxy configuration

Ensure your reverse proxy forwards the WebSocket upgrade headers (Upgrade and Connection), or connections will fail to establish — a very common cause of "it works on one server but not behind the proxy".

Putting it together

Sticky sessions keep each client on one instance; the Redis adapter keeps all instances in sync. With both, Socket.IO scales horizontally. Monitor connection counts as part of production monitoring.

Frequently asked questions

Why do I need sticky sessions?

Because a WebSocket connection lives on one instance. If the load balancer sends a client's follow-up traffic elsewhere, the connection breaks. Sticky sessions keep each client on its instance.

What does the Redis adapter actually do?

It shares Socket.IO events across instances via Redis pub/sub, so a message broadcast on one instance is delivered to clients connected to every other instance. Without it, broadcasts only reach one instance's clients.

My WebSockets fail behind Nginx — why?

Almost always missing upgrade headers. Ensure the proxy passes Upgrade and Connection: upgrade so the WebSocket handshake completes.

Was this article helpful?