Node.js cookbook · Advanced

Scale real-time Socket.IO across instances

Broadcast chat messages to rooms when users are connected to different Node instances.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Use Socket.IO with the Redis adapter so io.to(room).emit() reaches sockets on every instance. Authenticate in a connection middleware, authorize room joins, validate and rate-limit incoming events, and enable sticky sessions at the load balancer if HTTP long-polling fallback is used.

Solution

import { createServer } from "node:http";
import { Server } from "socket.io";
import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from "redis";

const httpServer = createServer(app);
const pub = createClient({ url: process.env.REDIS_URL });
const sub = pub.duplicate();
await Promise.all([pub.connect(), sub.connect()]);

const io = new Server(httpServer, { adapter: createAdapter(pub, sub), cors: { origin: "https://app.example.com", credentials: true } });

io.use(async (socket, next) => {
  try {
    socket.data.user = await verifyToken(socket.handshake.auth.token);
    next();
  } catch {
    next(new Error("unauthorized"));
  }
});

io.on("connection", (socket) => {
  socket.on("join", async (roomId: string, ack) => {
    if (!(await rooms.canJoin(socket.data.user.id, roomId))) return ack?.({ ok: false });
    await socket.join(`room:${roomId}`);
    ack?.({ ok: true });
  });
  socket.on("message", async ({ roomId, text }: { roomId: string; text: string }) => {
    if (!socket.rooms.has(`room:${roomId}`) || typeof text !== "string" || text.length > 2000) return;
    const message = await messages.save(roomId, socket.data.user.id, text);
    io.to(`room:${roomId}`).emit("message", message);
  });
});

httpServer.listen(3000);

Pitfalls

  • No auth on the socket handshake.
  • Trusting client-sent room IDs without authorization.
  • Missing sticky sessions with polling transport across instances.

Variations

  • Plain ws + Redis pub/sub for minimal overhead.
  • Managed realtime services for global scale.

Further reading: Socket.IO: Redis adapter

Reference: https://socket.io/docs/v4/redis-adapter/

More Node.js recipes

Was this page helpful?