What Is a WebSocket Connection? How It Works
WebSocket is a protocol that enables real-time, two-way communication between a browser and a server over a single, persistent TCP connection. Unlike HTTP where every interaction requires a new request, WebSocket lets both sides push messages to each other at any time.
The Problem WebSocket Solves
Traditional HTTP is request-response: the browser asks, the server answers, the connection closes. This works well for loading pages and fetching data, but it's terrible for real-time features.
Before WebSocket, developers used workarounds like polling (requesting new data every few seconds) and long-polling (keeping a request open until new data arrives). Both waste resources and add latency.
| Technique | How It Works | Latency | Server Load |
|---|---|---|---|
| Polling | Request every N seconds | N seconds average | High (many requests) |
| Long-polling | Request, wait, respond, repeat | ~0ms (when ready) | Medium (1 connection/client) |
| Server-Sent Events | One-way server → browser push | ~0ms | Low (read-only) |
| WebSocket | Persistent two-way channel | ~0ms | Low (1 connection/client) |
How WebSocket Works
Step 1: The HTTP Upgrade Handshake
A WebSocket connection starts as an HTTP request. The browser sends an upgrade request:
The server responds with 101 Switching Protocols:
Step 2: Persistent Bidirectional Channel
After the handshake, the TCP connection stays open and switches to the WebSocket protocol. Both sides can now send "frames" (messages) to each other at any time:
Step 3: Connection Lifecycle
WebSocket vs HTTP
| Property | HTTP | WebSocket |
|---|---|---|
| Communication | Request → Response (one direction) | Full duplex (both directions simultaneously) |
| Connection | New connection per request (HTTP/1.1) or multiplexed (HTTP/2) | Single persistent connection |
| Who initiates messages | Only client can initiate | Either side can send at any time |
| Header overhead | Full headers on every request (~500-800 bytes) | Tiny frames after handshake (~2-6 bytes header) |
| Latency | New connection overhead per request | Near-zero (connection already open) |
| State | Stateless by default | Stateful — connection persists |
| Protocol | HTTP/1.1, HTTP/2, HTTP/3 | ws:// or wss:// (after HTTP upgrade) |
| Port | 80 (http) / 443 (https) | 80 (ws) / 443 (wss) — same ports |
| Caching | Yes (GET responses) | No — live stream data |
| Load balancers | Simple (any server) | Sticky sessions required (or pub/sub) |
JavaScript: Basic WebSocket Client
Node.js Server (with ws library)
When to Use WebSocket
- Real-time chat and messaging apps
- Live collaborative editing (docs, whiteboards)
- Multiplayer games (position, state sync)
- Live sports scores, stock tickers, crypto prices
- Real-time dashboards and monitoring
- Push notifications with immediate delivery
- REST APIs and data fetching (one-shot operations)
- File uploads and downloads
- Updates less frequent than every 30 seconds
- Cacheable responses (GET requests)
- One-way streaming (SSE is simpler)
- Simple request-response patterns
Common WebSocket Issues
Implement ping/pong heartbeats. The ws library lets you configure pingInterval. Many proxies and load balancers close idle connections after 60 seconds. Send a ping every 30 seconds to keep the connection alive.
WebSocket requires sticky sessions (all messages from one client go to the same server). Alternatively, use Redis pub/sub or a message broker so any server can relay messages to any client. Nginx supports WebSocket proxy with proxy_pass and Upgrade headers.
Always listen for the "close" event and clean up client-side state. On the server, track connected clients in a Set and delete them on disconnect. Never store WebSocket connections in global state without cleanup.
wss:// (secure WebSocket) requires TLS. Your reverse proxy (Nginx, Caddy) must be configured to forward WebSocket upgrades correctly. For Nginx: include proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
Frequently Asked Questions
What is the difference between WebSocket and Socket.IO?
WebSocket is a standard browser API and protocol (RFC 6455). Socket.IO is a JavaScript library that uses WebSocket internally but adds: automatic reconnection, room/namespace support, fallback to HTTP long-polling when WebSocket is blocked, and its own message encoding. Socket.IO clients and servers are tightly coupled — you can't use a plain WebSocket client with a Socket.IO server. For new projects, raw WebSocket with a small library like ws (Node.js) is often sufficient.
Does WebSocket work behind firewalls and proxies?
Usually yes, because WebSocket uses the same ports as HTTP (80) and HTTPS (443). Most corporate firewalls allow these. However, some older proxy servers may not support the HTTP Upgrade mechanism and will drop WebSocket connections. wss:// (secure WebSocket, port 443) has the highest firewall compatibility since HTTPS traffic is rarely blocked.
How many WebSocket connections can a server handle?
A single server can typically handle tens of thousands of concurrent WebSocket connections. Each connection consumes a file descriptor and some memory (~10-50KB per connection depending on your implementation). Node.js with the ws library can handle 100,000+ concurrent connections on a single process with proper tuning. For millions of connections, use horizontal scaling with a pub/sub system like Redis to distribute messages across servers.
Is WebSocket supported in all browsers?
Yes. WebSocket has been supported in all major browsers since 2012 (IE 10+, Chrome 16+, Firefox 11+, Safari 6+). As of 2026, browser support is effectively universal. The WebSocket API is available as a global in both browsers and Node.js (version 22+ includes WebSocket natively).
Key Takeaways
- WebSocket is a persistent, full-duplex protocol — both sides can send messages at any time.
- It starts as an HTTP request then upgrades to a persistent TCP connection.
- Use it for real-time features: chat, live data, collaborative editing, games.
- Use HTTP (REST) for data fetching, file transfers, and anything that doesn't need live updates.
- Implement heartbeats and reconnect logic — connections can drop for network reasons.
- wss:// (port 443) has the best firewall compatibility — always use it in production.