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.

MT

Michael Torres

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.

MT

About Michael Torres

Michael Torres is the Backend Lead at Jishu Labs with expertise in real-time systems and distributed architectures.

Related Articles

Ready to Build Your Next Project?

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

Top-Rated
Software Development
Company

Ready to Get Started?

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

SCHEDULE MY CALL