WebSockets: First Principles Guide

A practical intro for readers coming from request-response HTTP who want the cleanest mental model for what WebSockets change, how the connection actually behaves, and why Durable Objects fit room-style coordination so well.

Why WebSockets Exist

HTTP and REST are good when the client asks and the server replies, then the interaction is mostly over.

Client asks -> Server responds -> connection mostly done

That works well for:

GET profile
POST order
PUT update
DELETE item

It breaks down for real-time things where the server needs to push data without the client polling constantly.

The Core Shift

Client connects once
Connection stays open
Client and server can both send anytime

That is the essence of WebSockets. It is a long-lived, bidirectional connection rather than a sequence of short request-response exchanges.

REST / HTTP WebSocket
requestopening handshake and later messages
responsehandshake response and later messages
GET or POSTno methods after connection opens
statelessstateful connection
client asks, server repliesboth sides can send anytime
JSON bodytext or binary WebSocket messages
/api/foows:// or wss:// URL

It Is an Upgrade

The opening step is not "promotion." It is an HTTP upgrade handshake.

GET /room/test/ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade

HTTP/1.1 101 Switching Protocols

That `101` means the connection switches from HTTP semantics to WebSocket protocol semantics.

Lifecycle

1. Client creates WebSocket
2. HTTP Upgrade handshake happens
3. Server accepts
4. Connection becomes OPEN
5. Both sides send messages
6. Ping or pong may keep it alive
7. One side closes
8. Connection becomes CLOSED

Browser-side states usually move through `CONNECTING`, `OPEN`, `CLOSING`, and `CLOSED`.

Basic Events

ws.onopen = () => {};
ws.onmessage = (event) => {};
ws.onerror = () => {};
ws.onclose = () => {};

The four events you usually care about are `open`, `message`, `error`, and `close`.

Messages vs Frames

At application level you think in messages. At protocol level WebSocket uses frames such as text, binary, close, ping, and pong frames.

ws.send(JSON.stringify({ type: "chat", text: "hello" }));

Most application code deals with messages, not raw frames.

Server-Side Mental Model

REST:
request comes in
handler runs
response goes out
done

WebSocket:
connection comes in
store it
handle messages
keep it alive until close

Different Configurations

You can run WebSockets directly on a server, behind a load balancer, or through Cloudflare Worker plus Durable Object routing.

Browser -> Worker -> ChatRoom DO

Why DO Fits

One room or session often needs one live coordinator. That is why Durable Objects fit room-style WebSocket architectures naturally.

room:test
  connected sockets:
    - client A
    - client B
    - client C

Advanced Concepts

  • ping and pong for keepalive or dead-connection detection
  • backpressure when sender is faster than receiver
  • reconnect after drop
  • heartbeat for app-level liveness
  • auth during handshake
  • subprotocol agreement
  • close codes
  • hibernation as a Cloudflare-specific DO concept

Core Mental Model

HTTP = short conversation
WebSocket = long phone call
DO WebSocket = one room manager holding many phone calls

That is the simplest framing that stays useful even as the implementation gets more advanced.

Memory Line

WebSockets replace short request-response exchanges with one long-lived bidirectional connection. Durable Objects fit when one room, document, or session needs one live owner for many such connections.

Standalone explainer