Durable Objects

by cloudflareb052c32bab7dNo license3K starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 7 days ago

Build, debug, or review Cloudflare Durable Objects code for persistent state and coordination.

AI-generated overview

Guides building, debugging, and reviewing Cloudflare Durable Objects code for stateful coordination.

What it does
Provides instructions and reference material for implementing Cloudflare Durable Objects, covering storage, concurrency, RPC methods, alarms, WebSocket handlers, and Wrangler configuration. It includes quick-reference code patterns, critical rules, anti-patterns, and stub creation examples, plus bundled reference files on rules, testing, and Workers. It points to Cloudflare documentation for current API details.
When to use it
Use when creating new Durable Object classes, implementing RPC, alarms, or WebSocket handlers, reviewing existing Durable Objects code, configuring Wrangler bindings and migrations, or writing tests with Cloudflare's Vitest integration.
Requirements
No scripts; instructions and reference documents only. Requires network access to fetch Cloudflare documentation, and assumes a Cloudflare Workers project with Wrangler and the Cloudflare Vitest integration for testing.

Durable Objects

Build stateful, coordinated applications on Cloudflare's edge using Durable Objects.

Retrieval Sources

Your knowledge of Durable Objects APIs and configuration may be outdated. Prefer retrieval over pre-training for any Durable Objects task.

Fetch the relevant doc page when implementing features.

When to Use

  • Creating new Durable Object classes for stateful coordination
  • Implementing RPC methods, alarms, or WebSocket handlers
  • Reviewing existing DO code for best practices
  • Configuring wrangler.jsonc/toml for DO bindings and migrations
  • Writing tests with Cloudflare’s Vitest integration
  • Designing sharding strategies and parent-child relationships

Reference Documentation

  • ./references/rules.md - Core rules, storage, concurrency, RPC, alarms
  • Testing reference - Current Vitest documentation, migration choices, and test selection
  • ./references/workers.md - Workers handlers, types, wrangler config, observability

Search: blockConcurrencyWhile, idFromName, getByName, setAlarm, sql.exec

Core Principles

Use Durable Objects For

NeedExample
CoordinationChat rooms, multiplayer games, collaborative docs
Strong consistencyInventory, booking systems, turn-based games
Per-entity storageMulti-tenant SaaS, per-user data
Persistent connectionsWebSockets, real-time notifications
Scheduled work per entitySubscription renewals, game timeouts

Do NOT Use For

  • Stateless request handling (use plain Workers)
  • Maximum global distribution needs
  • High fan-out independent requests

Quick Reference

Wrangler Configuration

jsonc
// wrangler.jsonc{  "durable_objects": {    "bindings": [{ "name": "MY_DO", "class_name": "MyDurableObject" }]  },  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyDurableObject"] }]}

Basic Durable Object Pattern

typescript
import { DurableObject } from "cloudflare:workers";
export interface Env {  MY_DO: DurableObjectNamespace<MyDurableObject>;}
export class MyDurableObject extends DurableObject<Env> {  constructor(ctx: DurableObjectState, env: Env) {    super(ctx, env);    ctx.blockConcurrencyWhile(async () => {      this.ctx.storage.sql.exec(`        CREATE TABLE IF NOT EXISTS items (          id INTEGER PRIMARY KEY AUTOINCREMENT,          data TEXT NOT NULL        )      `);    });  }
  async addItem(data: string): Promise<number> {    const result = this.ctx.storage.sql.exec<{ id: number }>(      "INSERT INTO items (data) VALUES (?) RETURNING id",      data    );    return result.one().id;  }}
export default {  async fetch(request: Request, env: Env): Promise<Response> {    const stub = env.MY_DO.getByName("my-instance");    const id = await stub.addItem("hello");    return Response.json({ id });  },};

Critical Rules

  1. Model around coordination atoms - One DO per chat room/game/user, not one global DO
  2. Use getByName() for deterministic routing - Same input = same DO instance
  3. Use SQLite storage - Configure new_sqlite_classes in migrations
  4. Initialize in constructor - Use blockConcurrencyWhile() for schema setup only
  5. Use RPC methods - Not fetch() handler (compatibility date >= 2024-04-03)
  6. Persist first, cache second - Always write to storage before updating in-memory state
  7. One alarm per DO - setAlarm() replaces any existing alarm

Anti-Patterns (NEVER)

  • Single global DO handling all requests (bottleneck)
  • Using blockConcurrencyWhile() on every request (kills throughput)
  • Storing critical state only in memory (lost on eviction/crash)
  • Using await between related storage writes (breaks atomicity)
  • Holding blockConcurrencyWhile() across fetch() or external I/O

Stub Creation

typescript
// Deterministic - preferred for most casesconst stub = env.MY_DO.getByName("room-123");
// From existing ID stringconst id = env.MY_DO.idFromString(storedIdString);const stub = env.MY_DO.get(id);
// New unique ID - store mapping externallyconst id = env.MY_DO.newUniqueId();const stub = env.MY_DO.get(id);

Storage Operations

typescript
// SQL (synchronous, recommended)this.ctx.storage.sql.exec("INSERT INTO t (c) VALUES (?)", value);const rows = this.ctx.storage.sql.exec<Row>("SELECT * FROM t").toArray();
// KV (async)await this.ctx.storage.put("key", value);const val = await this.ctx.storage.get<Type>("key");

Alarms

typescript
// Schedule (replaces existing)await this.ctx.storage.setAlarm(Date.now() + 60_000);
// Handlerasync alarm(): Promise<void> {  // Process scheduled work  // Optionally reschedule: await this.ctx.storage.setAlarm(...)}
// Cancelawait this.ctx.storage.deleteAlarm();

Testing

Read the testing reference before configuring a suite or writing Durable Object tests. It routes to current setup, APIs, and examples and identifies the behavior to cover.

Source and attribution

Source:cloudflare/skillsinskills/durable-objectsat commitb052c32

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal