Back to Blog
web-dev

Building Real-Time Applications with WebSockets, Redis, and Node.js

Build scalable real-time features like chat, notifications, and live updates using WebSockets with Redis pub/sub for horizontal scaling.

NyxaLabs Team
Building Real-Time Applications with WebSockets, Redis, and Node.js

Real-time features are table stakes for modern applications. Whether it's chat, notifications, or live dashboards, users expect instant updates. Here's how to build scalable real-time systems.

Why WebSockets Over Polling?

Long polling creates unnecessary HTTP overhead. WebSockets maintain persistent connections, reducing latency from hundreds of milliseconds to single-digit milliseconds.

Setting Up Socket.io with Express

import express from "express";
import { createServer } from "http";
import { Server } from "socket.io";

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
  cors: {
    origin: process.env.FRONTEND_URL,
    credentials: true,
  },
});

io.on("connection", (socket) => {
  console.log(`Client connected: ${socket.id}`);
  
  socket.on("join-room", (roomId) => {
    socket.join(roomId);
  });
  
  socket.on("message", (data) => {
    io.to(data.roomId).emit("message", data);
  });
});

The Scaling Problem

A single Node.js server can handle ~10,000 concurrent WebSocket connections. But what happens when you need multiple servers? Connections are stateful—a message sent to Server A won't reach clients connected to Server B.

Redis Pub/Sub for Horizontal Scaling

import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from "redis";

const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

await Promise.all([pubClient.connect(), subClient.connect()]);

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

Now messages are broadcast across all server instances through Redis pub/sub.

Room-Based Architecture

// User joins their personal notification channel
socket.join(`user:${userId}`);

// User joins a chat room
socket.join(`room:${roomId}`);

// Broadcast to specific user
io.to(`user:${userId}`).emit("notification", { ... });

// Broadcast to room
io.to(`room:${roomId}`).emit("message", { ... });

Authentication with Socket.io

import { verify } from "jsonwebtoken";

io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  try {
    const decoded = verify(token, process.env.JWT_SECRET!);
    socket.data.user = decoded;
    next();
  } catch (err) {
    next(new Error("Authentication failed"));
  }
});

Client-Side Implementation (React)

import { io, Socket } from "socket.io-client";
import { useEffect, useState } from "react";

export function useSocket(token: string) {
  const [socket, setSocket] = useState<Socket | null>(null);
  
  useEffect(() => {
    const newSocket = io(process.env.NEXT_PUBLIC_WS_URL!, {
      auth: { token },
      transports: ["websocket"],
    });
    
    setSocket(newSocket);
    return () => { newSocket.close(); };
  }, [token]);
  
  return socket;
}

Handling Reconnection

Network issues happen. Implement exponential backoff, message queuing during disconnection, and state synchronization on reconnect.

Production Checklist

Use sticky sessions with your load balancer, implement heartbeat monitoring, set up Redis Sentinel or Cluster for HA, and monitor connection counts and message throughput.

NyxaLabs Real-Time Solutions

We've built real-time systems handling millions of concurrent connections. From architecture design to implementation, we help you deliver instant experiences. Let's discuss your real-time requirements.

Tags

#WebSockets #Redis #Node.js #Real-Time #Socket.io #Tutorial

Want to Work With Us?

We're ready to help bring your ideas to life with cutting-edge technology.

Get In Touch