WebSockets are long-lived TCP connections that enable bi-directional, real-time communication between client and server. Both Cloudflare Durable Objects and Workers can act as WebSocket endpoints – either as a client or as a server. Because WebSocket sessions are long-lived, applications commonly use Durable Objects to accept either the client or server connection. While there are other use cases for using Workers exclusively with WebSockets, for example proxying WebSocket messages, WebSockets are most useful when combined with Durable Objects.
Because Durable Objects provide a single-point-of-coordination between Cloudflare Workers, a single Durable Object instance can be used in parallel with WebSockets to coordinate between multiple clients, such as participants in a chat room or a multiplayer game. Refer to Cloudflare Edge Chat Demo ↗ for an example of using Durable Objects with WebSockets.
Both Cloudflare Durable Objects and Workers can use the Web Standard WebSocket API to build applications, but a major differentiator of Cloudflare Durable Objects relative to other platforms is the ability to Hibernate WebSocket connections to save costs.
This guide covers:
Building a WebSocket server using Web Standard APIs
Using WebSocket Hibernation APIs.
WebSocket Standard API
WebSocket connections are established by making an HTTP GET request with the Upgrade: websocket header. A Cloudflare Worker is commonly used to validate the request, proxy the request to the Durable Object to accept the server side connection, and return the client side connection in the response.
Each WebSocket server in this example is represented by a Durable Object. This WebSocket server creates a single WebSocket connection and responds to all messages over that connection with the total number of accepted WebSocket connections. In the Durable Object's fetch handler we create client and server connections and add event listeners for relevant event types.
To execute this code, configure your wrangler.toml file to include a Durable Object binding and migration based on the namespace and class name chosen previously.
In addition to Workers WebSocket API, Cloudflare Durable Objects can use the WebSocket Hibernation API which extends the Web Standard WebSocket API to reduce costs. Specifically, billable Duration (GB-s) charges are not incurred during periods of inactivity. Note that other events, for example alarms, can prevent a Durable Object from being inactive and therefore prevent this cost saving.
The WebSocket consists of Cloudflare-specific extensions to the Web Standard WebSocket API. These extensions are either present on the DurableObjectState interface, or as handler methods on the Durable Object class.
The Worker used in the WebSocket Standard API example does not require any code changes to make use of the WebSocket Hibernation API. The changes to the Durable Object are described in the code sample below. In summary, DurableObjectState::acceptWebSocket is called to accept the server side of the WebSocket connection, and handler methods are defined on the Durable Object class for relevant event types rather than adding event listeners.
If an event occurs for a hibernated Durable Object's corresponding handler method, it will return to memory. This will call the Durable Object's constructor, so it is best to minimize work in the constructor when using WebSocket hibernation.
Similar to the WebSocket Standard API example, to execute this code, configure your wrangler.toml file to include a Durable Object binding and migration based on the namespace and class name chosen previously.
Keeps a copy of value associated with the WebSocket to survive hibernation. The value can be any type supported by the structured clone algorithm ↗, which is true of most types. If the value needs to be durable please use Durable Object Storage.
If you modify value after calling this method, those changes will not be retained unless you call this method again. The serialized size of value is limited to 2,048 bytes, otherwise this method will throw an error. If you need larger values to survive hibernation, use the Storage API and pass the corresponding key to this method so it can be retrieved later.
deserializeAttachment
deserializeAttachment(): any
Retrieves the most recent value passed to serializeAttachment(), or null if none exists.