
Durable Objects
Ship coordinated real-time or stateful logic on Cloudflare by modeling Durable Objects, SQLite storage, and sharding correctly.
Overview
Durable Objects is an agent skill for the Build phase that teaches Cloudflare coordination, sharding, and SQLite storage patterns for Durable Objects.
Install
npx skills add https://github.com/cloudflare/skills --skill durable-objectsWhat is this skill?
- One DO per coordination atom (room, session, tenant) with anti-patterns for global bottlenecks
- Parent-child DO hierarchies with SQL-backed match references and child init patterns
- Location hints (wnam, enam, weur, apac, etc.) for latency-sensitive placement
- SQLite-first storage via wrangler migrations and synchronous ctx.storage.sql.exec examples
- 10 location hint regions listed (wnam, enam, sam, weur, eeur, apac, oc, afr, me)
- SQLite recommended storage path with wrangler new_sqlite_classes migration pattern
Adoption & trust: 12.8k installs on skills.sh; 1.7k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are adding stateful coordination on Workers but risk a single global Durable Object, wrong storage API usage, or layouts that cannot scale per room or tenant.
Who is it for?
Solo builders shipping real-time or session-based apps on Cloudflare Workers who want agents to follow DO design rules from the first implementation pass.
Skip if: Teams not on Cloudflare, pure static sites without coordination, or projects that only need generic REST on traditional servers with no DO layer.
When should I use this skill?
Agent is implementing or reviewing Cloudflare Durable Objects classes, storage, or multi-DO coordination on Workers.
What do I get? / Deliverables
After the skill runs, your agent models one DO per logical unit, uses parent-child relationships where needed, and applies SQLite and location-hint patterns aligned with Cloudflare docs.
- Durable Object class designs with per-atom naming and storage queries
- Wrangler migration snippets for SQLite-backed DO classes
Recommended Skills
Journey fit
Stateful Workers patterns belong on the build shelf under backend because you apply them while designing APIs, rooms, and sessions—not during idea research alone. Durable Objects are a backend coordination primitive; the skill’s rules target DO class design, SQL storage, and parent-child DO graphs.
How it compares
Use for Cloudflare-specific DO architecture rules instead of generic Node backend snippets that ignore Workers isolation and DO storage semantics.
Common Questions / FAQ
Who is durable-objects for?
Indie and solo developers building on Cloudflare Workers who need agents to design Durable Objects around rooms, sessions, games, or tenants with SQLite-backed state.
When should I use durable-objects?
Use it during Build when scaffolding DO classes, wrangler migrations, sharding, or parent-child DO graphs for coordinated real-time features on Workers.
Is durable-objects safe to install?
Review the Security Audits panel on this Prism page and inspect the skill source in your repo before letting an agent run shell or deploy commands against your Cloudflare account.
SKILL.md
READMESKILL.md - Durable Objects
# Durable Objects Rules & Best Practices ## Design & Sharding ### Model Around Coordination Atoms Create one DO per logical unit needing coordination: chat room, game session, document, user, tenant. ```typescript // ✅ Good: One DO per chat room const stub = env.CHAT_ROOM.getByName(roomId); // ❌ Bad: Single global DO const stub = env.CHAT_ROOM.getByName("global"); // Bottleneck! ``` ### Parent-Child Relationships For hierarchical data, create separate child DOs. Parent tracks references, children handle own state. ```typescript // Parent: GameServer tracks match references // Children: GameMatch handles individual match state async createMatch(name: string): Promise<string> { const matchId = crypto.randomUUID(); this.ctx.storage.sql.exec( "INSERT INTO matches (id, name) VALUES (?, ?)", matchId, name ); const child = this.env.GAME_MATCH.getByName(matchId); await child.init(matchId, name); return matchId; } ``` ### Location Hints Influence DO creation location for latency-sensitive apps: ```typescript const id = env.GAME.idFromName(gameId, { locationHint: "wnam" }); ``` Available hints: `wnam`, `enam`, `sam`, `weur`, `eeur`, `apac`, `oc`, `afr`, `me`. ## Storage ### SQLite (Recommended) Configure in wrangler: ```jsonc { "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyDO"] }] } ``` SQL API is synchronous: ```typescript // Write this.ctx.storage.sql.exec( "INSERT INTO items (name, value) VALUES (?, ?)", name, value ); // Read const rows = this.ctx.storage.sql.exec<{ id: number; name: string }>( "SELECT * FROM items WHERE name = ?", name ).toArray(); // Single row const row = this.ctx.storage.sql.exec<{ count: number }>( "SELECT COUNT(*) as count FROM items" ).one(); ``` ### Migrations **Note:** `PRAGMA user_version` is **not supported** in Durable Objects SQLite storage. Use a `_sql_schema_migrations` table instead: ```typescript constructor(ctx: DurableObjectState, env: Env) { super(ctx, env); ctx.blockConcurrencyWhile(async () => this.migrate()); } private migrate() { this.ctx.storage.sql.exec(` CREATE TABLE IF NOT EXISTS _sql_schema_migrations ( id INTEGER PRIMARY KEY, applied_at TEXT NOT NULL DEFAULT (datetime('now')) ) `); const currentVersion = this.ctx.storage.sql .exec<{ version: number }>("SELECT COALESCE(MAX(id), 0) as version FROM _sql_schema_migrations") .one().version; if (currentVersion < 1) { this.ctx.storage.sql.exec(` CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, data TEXT); CREATE INDEX IF NOT EXISTS idx_items_data ON items(data); INSERT INTO _sql_schema_migrations (id) VALUES (1); `); } if (currentVersion < 2) { this.ctx.storage.sql.exec(` ALTER TABLE items ADD COLUMN created_at INTEGER; INSERT INTO _sql_schema_migrations (id) VALUES (2); `); } } ``` For production apps, consider [`durable-utils`](https://github.com/lambrospetrou/durable-utils#sqlite-schema-migrations) — provides a `SQLSchemaMigrations` class that tracks executed migrations both in memory and in storage. Also see [`@cloudflare/actors` storage utilities](https://github.com/cloudflare/actors/blob/main/packages/storage/src/sql-schema-migrations.ts) — a reference implementation of the same pattern used by the Cloudflare Actors framework. ### State Types | Type | Speed | Persistence | Use Case | |------|-------|-------------|----------| | Class properties | Fastest | Lost on eviction | Caching, active connections | | SQLite storage | Fast | Durable | Primary data | | External (R2, D1) | Variable | Durable, cross-DO | Large files, shared data | **Rule**: Always persist critical state to SQLite first, then update in-memory cache. ## Concurrency ### Input/Output Gates Storage operations automatically block other requests (input gates). Responses wait for writes (output gates). ```typescript async increment(): Promise<number> { // Safe: input gates block interleaving during storage o