Elite Durable Objects Workshop
Boost productivity with intelligent stateful coordination with RPC, SQLite, and WebSockets. Built for Claude Code with best practices and real-world patterns.
Durable Objects Workshop
Advanced Cloudflare Durable Objects development guide for building stateful edge applications including real-time collaboration, WebSocket servers, rate limiters, and distributed coordination systems.
When to Use This Skill
Choose Durable Objects when:
- Building real-time collaborative features (shared documents, cursors)
- Need WebSocket connections with persistent server-side state
- Implementing distributed rate limiting or counters
- Building game servers or chat systems at the edge
- Need strong consistency guarantees for specific entities
Consider alternatives when:
- Need simple caching — use Workers KV
- Need relational queries — use D1
- Need long-running background jobs — use Workers Queues
- Need global read-heavy data — use KV (Durable Objects are single-location)
Quick Start
# Activate Durable Objects workshop claude skill activate elite-durable-objects-workshop # Build a collaborative feature claude "Build a real-time collaborative document editor using Durable Objects" # Implement rate limiting claude "Create a distributed rate limiter with Durable Objects"
Example: WebSocket Chat Room
// Durable Object class export class ChatRoom { private sessions: Map<WebSocket, { name: string }> = new Map(); private state: DurableObjectState; constructor(state: DurableObjectState) { this.state = state; } async fetch(request: Request): Promise<Response> { const url = new URL(request.url); if (url.pathname === '/websocket') { if (request.headers.get('Upgrade') !== 'websocket') { return new Response('Expected WebSocket', { status: 400 }); } const pair = new WebSocketPair(); const [client, server] = Object.values(pair); const name = url.searchParams.get('name') || 'Anonymous'; this.sessions.set(server, { name }); server.accept(); server.addEventListener('message', (event) => { const message = JSON.stringify({ sender: name, text: event.data, timestamp: Date.now(), }); // Broadcast to all connected clients for (const [ws] of this.sessions) { if (ws !== server && ws.readyState === WebSocket.READY_STATE_OPEN) { ws.send(message); } } }); server.addEventListener('close', () => { this.sessions.delete(server); this.broadcast({ type: 'leave', name }); }); // Notify others this.broadcast({ type: 'join', name }); return new Response(null, { status: 101, webSocket: client }); } // REST endpoint for room info if (url.pathname === '/info') { return Response.json({ connectedUsers: Array.from(this.sessions.values()).map(s => s.name), count: this.sessions.size, }); } return new Response('Not found', { status: 404 }); } private broadcast(data: object) { const message = JSON.stringify(data); for (const [ws] of this.sessions) { if (ws.readyState === WebSocket.READY_STATE_OPEN) { ws.send(message); } } } } // Worker that routes to Durable Objects export default { async fetch(request: Request, env: Env): Promise<Response> { const url = new URL(request.url); const roomId = url.searchParams.get('room') || 'default'; const id = env.CHAT_ROOM.idFromName(roomId); const room = env.CHAT_ROOM.get(id); return room.fetch(request); }, };
Core Concepts
Durable Object Characteristics
| Feature | Description |
|---|---|
| Single Instance | Exactly one instance per ID, globally |
| In-Memory State | Fast access to state between requests |
| Persistent Storage | Transactional KV storage via state.storage |
| WebSocket Support | Native WebSocket handling with hibernation |
| Alarms | Scheduled future execution per object |
| Location | Runs near the first client that accesses it |
Use Case Patterns
| Pattern | Description | Example |
|---|---|---|
| Collaboration Hub | Central state for multi-user editing | Google Docs-style real-time editing |
| Entity Actor | One DO per entity managing its lifecycle | User session, game room, IoT device |
| Rate Limiter | Per-key rate limiting with precise counters | API rate limiting per customer |
| Queue Processor | Ordered processing of events per partition | Event sourcing per aggregate |
| Cache Coordinator | Consistent cache invalidation | Multi-region cache coherence |
// Rate Limiter Durable Object export class RateLimiter { private state: DurableObjectState; constructor(state: DurableObjectState) { this.state = state; } async fetch(request: Request): Promise<Response> { const now = Date.now(); const windowMs = 60_000; // 1 minute window const maxRequests = 100; // Get current window data const windowKey = `window:${Math.floor(now / windowMs)}`; const count = (await this.state.storage.get<number>(windowKey)) || 0; if (count >= maxRequests) { return Response.json( { error: 'Rate limit exceeded', retryAfter: Math.ceil((windowMs - (now % windowMs)) / 1000) }, { status: 429, headers: { 'Retry-After': String(Math.ceil((windowMs - (now % windowMs)) / 1000)) } } ); } await this.state.storage.put(windowKey, count + 1); // Clean up old windows const oldKey = `window:${Math.floor(now / windowMs) - 2}`; await this.state.storage.delete(oldKey); return Response.json({ remaining: maxRequests - count - 1, limit: maxRequests, reset: Math.ceil((windowMs - (now % windowMs)) / 1000), }); } }
Configuration
| Parameter | Description | Default |
|---|---|---|
class_name | Durable Object class name | Required |
script_name | Worker script containing the DO | Current worker |
websocket_hibernation | Enable WebSocket hibernation API | true |
storage_limit | Max storage per object | 1GB |
alarm_retry | Retry failed alarms | true |
Best Practices
-
Use WebSocket Hibernation API for connection-heavy applications — Standard WebSocket handling keeps the DO awake (and billing) while connections are idle. The Hibernation API suspends the DO between messages, dramatically reducing costs for chat/collaboration apps.
-
Design for single-threaded execution — Each Durable Object processes one request at a time. Design your state management assuming no concurrency within a single DO. Use
state.storage.transaction()for multi-key atomic operations. -
Use
idFromName()for deterministic routing,newUniqueId()for isolation —idFromName("user-123")always routes to the same DO instance, ideal for per-entity state.newUniqueId()creates isolated instances when you need guaranteed separation. -
Implement heartbeat and cleanup with Alarms — Use Durable Object Alarms to schedule cleanup of stale connections, expired data, and periodic state persistence. Alarms survive DO restarts and ensure cleanup happens even if no clients are connected.
-
Keep Durable Object storage small and focused — Store only the state needed for coordination. Offload large data to R2 or D1 and keep only references in the DO. Large storage slows down DO startup when it loads state from disk.
Common Issues
Durable Object starts responding slowly under load. Each DO is single-threaded — requests queue up if processing is slow. Optimize handler code, batch storage operations, and consider sharding load across multiple DO instances using consistent hashing.
WebSocket connections drop unexpectedly. Implement client-side reconnection with exponential backoff. On the server, use the close and error events to clean up session state. If using Hibernation API, handle the webSocketClose event handler properly.
Storage transactions fail with conflicts. Durable Object storage transactions use optimistic concurrency. If two operations modify the same keys, one will fail. Retry failed transactions with exponential backoff, and design key schemas to minimize conflicts between concurrent requests.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.