What Is a WebSocket? Real-Time, Two-Way Web Communication
A WebSocket is a protocol for full-duplex, persistent communication over a single TCP connection. Learn how it works, when to use it, and what the alternatives are.
A WebSocket is a protocol that opens a persistent, full-duplex channel between a browser and a server over a single TCP connection. Unlike the traditional HTTP request/response model — where the client asks, the server answers, and the connection closes — a WebSocket stays open, letting either side send data at any moment. That single shift unlocks a whole class of applications that feel genuinely live.
How the connection works
A WebSocket session starts as a plain HTTP request. The client sends an Upgrade header asking the server to switch protocols:
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
If the server agrees, it responds with 101 Switching Protocols, and from that point on the connection speaks the WebSocket wire format — small, low-overhead frames rather than full HTTP envelopes. The scheme changes too: unencrypted connections use ws://, and TLS-protected ones use wss:// (always prefer wss:// in production).
Once open, the channel is genuinely bidirectional. The server can push a message at any time — no polling, no waiting for the client to ask.
The browser API
Opening a WebSocket from JavaScript is a few lines:
const socket = new WebSocket("wss://example.com/live");
socket.addEventListener("open", () => {
socket.send(JSON.stringify({ type: "subscribe", channel: "prices" }));
});
socket.addEventListener("message", (event) => {
const data = JSON.parse(event.data);
console.log("received:", data);
});
socket.addEventListener("close", (event) => {
console.log("connection closed", event.code);
});
The WebSocket constructor, send(), and the message / open / close / error events are the whole surface area. Understanding the JavaScript event loop helps here — WebSocket callbacks are handled as tasks queued on the event loop, just like fetch responses.
Why it matters: real-time applications
The use cases that make WebSockets worth the added complexity:
- Chat and messaging — every participant receives messages as they’re sent, not on the next poll.
- Live dashboards — stock tickers, analytics, server-health monitors that need sub-second freshness.
- Multiplayer games — bidirectional state sync between players requires tight round-trip times.
- Collaborative editing — tools like Figma or live code editors need to stream cursor positions and edits instantly.
- Live notifications — push alerts without any client-side timer.
For anything where latency matters or where the server needs to initiate communication, WebSockets are the default choice.

Alternatives and when to reach for them
WebSockets aren’t always the right tool. The landscape of real-time options is wider than it looks:
| Technique | Direction | Notes |
|---|---|---|
| Short polling | Client → server | Simplest; wastes bandwidth, high latency |
| Long polling | Client → server | Holds connection open until data arrives; works everywhere |
| WebSocket | Both | Full duplex; best for interactive, bidirectional data |
| Server-Sent Events (SSE) | Server → client | One-way push; built on HTTP, auto-reconnects, simpler to proxy |
| WebTransport | Both | Newer; runs over HTTP/3 (QUIC), supports streams and datagrams |
Server-Sent Events are a strong choice when the server only needs to push — think live feeds, progress bars, or log streaming. They’re plain HTTP, which means they work through most proxies without configuration. WebSockets require proxy support for the Upgrade handshake, which can be a deployment headache.
WebTransport is the direction the web platform is heading. Built on QUIC (HTTP/3), it supports multiple independent streams and unreliable datagrams — useful for gaming and media. It’s still gaining browser and server support as of 2026.
If you’re evaluating the broader API landscape, or coming from a REST background, WebSockets represent a fundamentally different model: stateful, event-driven, and long-lived rather than stateless and request-scoped.
Scaling concerns
A single WebSocket server can handle thousands of concurrent connections — but scaling to many servers introduces coordination problems. Because connections are stateful and long-lived, you can’t route the same client to a different server on each request.
Two patterns address this:
- Sticky sessions — the load balancer pins a client to one backend for the life of the connection. Simple, but limits rebalancing.
- Pub/sub backplane — each server publishes messages to a shared broker (Redis Pub/Sub is common), and all servers relay relevant messages to their connected clients. This scales horizontally and survives individual server restarts.
Cloudflare’s developer platform offers Durable Objects, which co-locate WebSocket state with computation at the edge — an interesting alternative to the traditional backplane approach.
DNS also plays a role in WebSocket deployments: the initial HTTP upgrade goes to a hostname resolved through normal DNS lookups, so your DNS configuration affects which server a client reaches.
The takeaway
A WebSocket replaces the HTTP request/response cycle with a persistent, two-way channel that either side can write to at any time. Start with the browser WebSocket API, prefer wss:// everywhere, and reach for Server-Sent Events when you only need server push — they’re simpler to operate. When you scale past a single server, add a pub/sub backplane. For most real-time features, WebSockets are the fastest path from idea to working.
Keep reading
Takina · · 5 min read Server-Sent Events vs WebSockets: Which to Use
SSE streams one-way updates over plain HTTP; WebSockets open a full-duplex channel. How they differ and which fits your real-time feature.
Takina · · 4 min read What Is WebRTC? Real-Time Audio, Video, and Data
WebRTC lets browsers stream audio, video, and data directly between peers — no plugins. How getUserMedia, RTCPeerConnection, and ICE/STUN/TURN fit together.
Takina · · 4 min read TypeScript Abstract Classes, Explained
Abstract classes in TypeScript define shared implementation plus methods subclasses must fill in. How they differ from interfaces and when to reach for them.