PRO

Durable Object WebSocket Hibernation

A chat room Durable Object that holds open WebSockets without being pinned to memory, using ctx.acceptWebSocket() instead of ws.accept() so the runtime owns the sockets and the object can be evicted while every connection stays open. Built around the constraint that eviction erases all instance state: per-connection identity and subscriptions live in ws.serializeAttachment() under the 16,384 byte limit, never in a Map on the class, and the connection set is recovered from ctx.getWebSockets() on the first call after a wake. Covers tag-scoped fan out via acceptWebSocket(ws, tags) and getWebSockets(tag), the webSocketMessage, webSocketClose, and webSocketError class handlers that replace addEventListener, and a broadcast path that is correct on a cold instance. Heartbeats go through ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair("ping", "pong")), which answers without waking the object, and getWebSocketAutoResponseTimestamp() reaps stale connections off that signal for free.

Install
npx shadcn@latest add https://ui.aryank.space/r/durable-object-websocket-hibernation.json

Installs from ui.aryank.space. To add it by hand, copy the files in Files below, or register the @compronents namespace via the docs.

Visualization
between messages
chat room DO
Map<WebSocket, Session>
this.sessions.set(ws, meta) // in-memory state pins the DO awake

A chat room is quiet for 40 minutes but the Durable Object holding its sockets stays pinned in memory the whole time, billed for every idle second. Multiply by ten thousand quiet rooms and the bill is mostly silence.

Files

Dependencies
@cloudflare/[email protected]