Backend & APIs14 min read557 words

Real-Time Applications with WebSockets in 2026: Complete Implementation Guide

Build real-time features with WebSockets. Learn connection management, scaling strategies, and implementation patterns for chat, collaboration, and live updates.

JL

Jishu Labs

Real-time features are expected in modern applications - from chat and notifications to collaborative editing. WebSockets provide the foundation for bidirectional communication. This guide covers production patterns for building scalable real-time systems.

WebSocket Server Setup

typescript
// WebSocket server with Socket.io
import { Server } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { Redis } from 'ioredis';
import { verifyToken } from './auth';

const pubClient = new Redis(process.env.REDIS_URL!);
const subClient = pubClient.duplicate();

const io = new Server({
  cors: {
    origin: process.env.CLIENT_URL,
    credentials: true,
  },
  adapter: createAdapter(pubClient, subClient),
});

// Authentication middleware
io.use(async (socket, next) => {
  const token = socket.handshake.auth.token;
  
  if (!token) {
    return next(new Error('Authentication required'));
  }
  
  try {
    const user = await verifyToken(token);
    socket.data.user = user;
    next();
  } catch (error) {
    next(new Error('Invalid token'));
  }
});

// Connection handling
io.on('connection', (socket) => {
  const userId = socket.data.user.id;
  console.log(`User connected: ${userId}`);
  
  // Join user's personal room
  socket.join(`user:${userId}`);
  
  // Track online status
  pubClient.sadd('online-users', userId);
  io.emit('user:online', { userId });
  
  // Handle joining rooms
  socket.on('room:join', async (roomId: string) => {
    // Verify user has access to room
    const hasAccess = await checkRoomAccess(userId, roomId);
    if (!hasAccess) {
      socket.emit('error', { message: 'Access denied' });
      return;
    }
    
    socket.join(`room:${roomId}`);
    socket.to(`room:${roomId}`).emit('room:user-joined', {
      userId,
      roomId,
    });
  });
  
  // Handle messages
  socket.on('message:send', async (data) => {
    const message = await saveMessage({
      roomId: data.roomId,
      userId,
      content: data.content,
    });
    
    io.to(`room:${data.roomId}`).emit('message:new', message);
  });
  
  // Handle disconnection
  socket.on('disconnect', () => {
    pubClient.srem('online-users', userId);
    io.emit('user:offline', { userId });
  });
});

io.listen(3001);

Client Implementation

typescript
// React client with reconnection and state management
import { io, Socket } from 'socket.io-client';
import { create } from 'zustand';

interface SocketState {
  socket: Socket | null;
  connected: boolean;
  connect: (token: string) => void;
  disconnect: () => void;
}

export const useSocketStore = create<SocketState>((set, get) => ({
  socket: null,
  connected: false,
  
  connect: (token: string) => {
    const socket = io(process.env.NEXT_PUBLIC_WS_URL!, {
      auth: { token },
      reconnection: true,
      reconnectionAttempts: 5,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 5000,
    });
    
    socket.on('connect', () => {
      console.log('Connected to WebSocket');
      set({ connected: true });
    });
    
    socket.on('disconnect', (reason) => {
      console.log('Disconnected:', reason);
      set({ connected: false });
    });
    
    socket.on('connect_error', (error) => {
      console.error('Connection error:', error.message);
    });
    
    set({ socket });
  },
  
  disconnect: () => {
    const { socket } = get();
    if (socket) {
      socket.disconnect();
      set({ socket: null, connected: false });
    }
  },
}));

// Custom hook for real-time messages
function useMessages(roomId: string) {
  const socket = useSocketStore((state) => state.socket);
  const [messages, setMessages] = useState<Message[]>([]);
  
  useEffect(() => {
    if (!socket) return;
    
    // Join room
    socket.emit('room:join', roomId);
    
    // Listen for messages
    socket.on('message:new', (message: Message) => {
      setMessages((prev) => [...prev, message]);
    });
    
    // Cleanup
    return () => {
      socket.off('message:new');
      socket.emit('room:leave', roomId);
    };
  }, [socket, roomId]);
  
  const sendMessage = useCallback((content: string) => {
    socket?.emit('message:send', { roomId, content });
  }, [socket, roomId]);
  
  return { messages, sendMessage };
}

Scaling Strategies

WebSocket Scaling Patterns

Horizontal Scaling:

- Use Redis adapter for multi-server pub/sub

- Implement sticky sessions or socket affinity

- Consider managed solutions (Pusher, Ably)

Performance:

- Use binary protocols (MessagePack) for large payloads

- Implement message batching for high-frequency updates

- Use room-based broadcasting instead of individual emissions

Reliability:

- Implement heartbeat/ping-pong for connection health

- Add message acknowledgments for critical events

- Use message queues for guaranteed delivery

Conclusion

WebSockets enable powerful real-time features when implemented correctly. Focus on proper authentication, connection management, and scaling patterns from the start.

Need help building real-time features? Contact Jishu Labs for expert backend development consulting.

JL

About Jishu Labs

Jishu Labs is a technology expert at Jishu Labs, specializing in backend & apis and software development best practices.

Related Articles

Ready to Build Your Next Project?

Let's discuss how our expert team can help bring your vision to life.

AI Tools,
Built
End-to-End

Ready to Get Started?

Get consistent results. Collaborate in real-time.
Build Intelligent Apps. Work with Jishu Labs.

SCHEDULE MY CALL