WebSockets & Real-Time Communication
WebSockets provide a persistent, bidirectional connection between client and server, enabling real-time features like chat, presence, live dashboards, collaborative editing, and notifications — without the overhead of constant polling.
The protocol is the easy part. The real work is operational: authenticating long-lived connections, scaling broadcasts across many server instances, and handling slow or disconnected clients.
TL;DR
- Use WebSockets for bidirectional, low-latency interaction.
- Use SSE when you only need server → client streaming (it's simpler).
- Authenticate on connect and authorize every action (joins, sends).
- Plan scaling early: sticky sessions + a shared pub/sub for cross-instance broadcasts.
Quick Example
A minimal echo server with the ws library — an HTTP request upgrades into a persistent socket:
Choosing a Transport
A WebSocket starts as an HTTP request with an Upgrade handshake; after the upgrade, frames flow over the same TCP connection. Pick a message format — JSON for simplicity, binary for performance at scale.
Socket.IO vs raw WebSockets
Socket.IO adds reconnects, rooms/namespaces, and fallbacks at some overhead; raw WebSockets give you minimal overhead and full control. Choose based on your scale and how much you want to build yourself.
Authentication & Authorization
Authenticate on connect: validate a cookie session or a bearer token presented in the handshake. Authorize every action afterward — joining a room, subscribing to a topic, sending a message — because an authenticated connection isn't authorized for everything. See Authentication.
Scaling
Sticky sessions
With multiple instances behind a load balancer, clients usually must stay pinned to the instance holding their connection.
Shared pub/sub for broadcasts
To broadcast across instances, publish to a broker (Redis pub/sub, NATS, Kafka); each instance forwards to its own connected clients. See Message Queues.
Backpressure
Slow clients cause server buffers to grow and memory to climb. Mitigate by dropping/limiting per-client messages, disconnecting slow consumers, or sending snapshots instead of every delta.
Reliability
- Reconnect with exponential backoff, then resume subscriptions and replay missed events where possible.
- Delivery isn't guaranteed by WebSockets alone — if you need guarantees, add message IDs and acknowledgements, and persist events so clients can catch up.
Common Mistakes
Putting tokens in the query string
Authenticating once, then never authorizing
FAQ
WebSockets or Server-Sent Events?
Use WebSockets when the client also needs to send frequently (chat, collaboration, games). Use SSE when you only push server → client (notifications, dashboards) — it's simpler, runs over plain HTTP, and reconnects automatically.
How do I scale WebSockets across multiple servers?
Use sticky sessions so a client stays on its connection's instance, and a shared pub/sub broker so a message published on one instance reaches clients connected to others.
Do WebSockets guarantee message delivery?
No. The connection can drop and messages can be missed. For guarantees, add message IDs and acks, and persist events so a reconnecting client can replay what it missed.
How should I authenticate a WebSocket?
Validate a session cookie or a token in the handshake at connect time — not in the URL query string — then authorize each action the client attempts.
Related Topics
- Message Queues — Cross-instance broadcast and fan-out
- Microservices — Real-time across services
- Authentication — Securing the connection
- API Security — Rate limiting and payload validation
- GraphQL — Subscriptions over WebSockets
- Phoenix Framework — Channels and LiveView over WebSockets