BlogWebSockets in the Real World: What the Tutorials Don't Cover
Web Development

WebSockets in the Real World: What the Tutorials Don't Cover

By Madhukar May 12, 2026 6 min read

WebSockets are straightforward to get working in a demo. They become significantly more complex to operate reliably in production. Here is what I learned building the real-time collaboration features in Devpads.

The Reconnection Problem

Browsers close WebSocket connections constantly — when a user locks their phone, when they switch tabs for a while, when their WiFi drops and reconnects. Your client code must handle reconnection gracefully.

A naive reconnect loop will hammer your server. Use exponential backoff:

javascript
class ReconnectingWebSocket {
  constructor(url) {
    this.url = url;
    this.retryDelay = 1000;
    this.maxDelay = 30000;
    this.connect();
  }

  connect() {
    this.ws = new WebSocket(this.url);

    this.ws.onclose = () => {
      setTimeout(() => {
        this.retryDelay = Math.min(this.retryDelay * 2, this.maxDelay);
        this.connect();
      }, this.retryDelay);
    };

    this.ws.onopen = () => {
      this.retryDelay = 1000; // Reset on successful connect
    };
  }
}

Message Ordering Is Not Guaranteed

TCP guarantees ordered delivery, but between your application logic on the client and server, order can break down. If user A sends edit at position 10 and user B simultaneously sends an insert at position 8, both can arrive in an order that makes one invalid.

For simple use cases, a sequence number and server-side ordering is sufficient. For true conflict-free collaboration, look into CRDTs (Conflict-free Replicated Data Types) — complex but worth understanding conceptually.

Connection State Must Be Visible to Users

Users need to know when they are disconnected. A collaborative editor where a user types for two minutes while silently disconnected, then loses all changes on reconnect, is a terrible experience.

Maintain explicit connection state in your UI:

javascript
const [connectionState, setConnectionState] = useState('connecting');
// 'connecting' | 'connected' | 'disconnected' | 'reconnecting'

Show a clear indicator — a status dot, a banner, something — whenever the state is not 'connected'. Do not let users type into a void.

Horizontal Scaling Requires Pub/Sub

A WebSocket connection is persistent and lives on one server. When you scale to multiple server instances, users connected to different servers cannot receive each other's messages without a pub/sub layer.

Redis Pub/Sub (or similar) is the standard solution: every server subscribes to a channel and publishes incoming messages to it, ensuring all connected servers broadcast to their respective clients.

M

Madhukar

Founder & Lead Engineer, Devpads

Building lightweight, high-performance, and privacy-first developer utilities. Madhukar specializes in modern web architectures, code editor tooling, and developer workspace experiences. Read more about our mission on our dedicated About Page or get in touch via Contact Us.

Stack: React · Vite · Tailwind · FastAPI · PostgreSQL