Working with WebSockets

1. Installing socket.io Package

Example: Install

npm i socket.io @socket.io/redis-adapter ioredis

2. Creating Socket.io Server

Example: Attach to HTTP server

import http from "node:http";
import { Server } from "socket.io";

const server = http.createServer(app);
const io = new Server(server, { cors: { origin: "https://app.example.com" } });
server.listen(3000);

3. Handling Connection Events

Example: connection

io.on("connection", (socket) => {
  logger.info({ id: socket.id }, "client connected");
  socket.on("disconnect", (reason) => logger.info({ id: socket.id, reason }, "disconnected"));
});

4. Emitting Events

Example: socket.emit

socket.emit("welcome", { msg: "hello", id: socket.id });

5. Broadcasting Events

MethodRecipients
socket.emitThis socket only
socket.broadcast.emitAll except this socket
io.emitEvery connected socket
io.to(room).emitAll in room
socket.to(room).emitAll in room except sender

6. Joining Rooms

Example: Join room

socket.join(`user:${socket.user.id}`);
socket.join(`room:${roomId}`);

7. Leaving Rooms

Example: Leave

socket.leave(`room:${roomId}`);

8. Emitting to Rooms

Example: Targeted emit

io.to(`room:${roomId}`).emit("message", { from: socket.user.id, text });

9. Handling Disconnection

Example: Cleanup

socket.on("disconnect", async (reason) => {
  await presence.remove(socket.user.id);
  io.to(`org:${socket.user.orgId}`).emit("presence:offline", { userId: socket.user.id });
});

10. Using Namespaces

Example: Admin namespace

const admin = io.of("/admin");
admin.use(requireAdminSocket);
admin.on("connection", (socket) => {
  socket.emit("metrics", currentMetrics());
});

11. Implementing Middleware

Example: JWT auth on handshake

io.use((socket, next) => {
  try {
    const token = socket.handshake.auth?.token;
    socket.user = jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch (err) {
    next(new Error("Unauthorized"));
  }
});
Note: For multi-instance deployments, attach the Redis adapter so emits are delivered across nodes: io.adapter(createAdapter(pubClient, subClient)).