durable-objects — Claude Code skill: what it does, how to install
This skill helps build, debug, and review Cloudflare Durable Objects for state, coordination, and persistent connections.
npx skills add cloudflare/skills --skill durable-objects -a claude-codeWhat durable-objects does
The skill guides an agent through Durable Object classes, RPC methods, alarms, and WebSocket handlers. It also covers bindings and migrations in wrangler.jsonc or wrangler.toml, deterministic routing with getByName(), and SQLite storage.
Its references cover storage, concurrency, RPC, alarms, Workers configuration, observability, and testing with Cloudflare’s Vitest integration. The workflow favors retrieving current documentation before implementation. Tests should be planned with references/testing.md.
The guidance draws a clear boundary around the product: Durable Objects fit coordination, consistent state, per-entity storage, and persistent connections. They do not fit stateless request handling or maximum global distribution. Because blockConcurrencyWhile() must not span fetch() or external I/O, that detail deserves a specific review check.
What it helps with
- create a Durable Object class for entity state
- configure bindings and migrations in
wrangler.jsonc - route requests deterministically with
getByName() - review RPC, alarm, and WebSocket handlers
- write tests with Cloudflare’s Vitest integration
Example prompts for the agent
- Create a Durable Object for a chat room with SQLite storage and RPC methods.
- Review this Durable Objects code for migration, concurrency, and `blockConcurrencyWhile()` problems.
- Configure `wrangler.jsonc` for `MyDurableObject`, the `MY_DO` binding, and a SQLite migration.
How to install durable-objects
1Skills CLI (Vercel)
npx skills add cloudflare/skills --skill durable-objects -a claude-code2Manually: put the files in place
~/.claude/skills/durable-objects/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/durable-objects/
1Skills CLI (Vercel)
npx skills add cloudflare/skills --skill durable-objects -a codex2Manually: put the files in place
.agents/skills/durable-objects/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add cloudflare/skills --skill durable-objects -a cursor2Manually: put the files in place
.cursor/skills/durable-objects/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install cloudflare/skills durable-objects2Manually: put the files in place
.github/skills/durable-objects/SKILL.md1Skills CLI (Vercel)
npx skills add cloudflare/skills --skill durable-objects -a gemini-cli2Platform CLI
gemini skills install https://github.com/cloudflare/skills --path skills/durable-objectsManually: put the files in place
.devin/skills/durable-objects/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add cloudflare/skills --skill durable-objects -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
From the same set18
The whole set →Similar
Questions about durable-objects
How do I install durable-objects in Claude Code?
Run npx skills add cloudflare/skills --skill durable-objects -a claude-code, run the same command again, then use ~/.claude/skills/durable-objects/SKILL.md.
What does durable-objects do?
It helps an agent build and review Cloudflare Durable Objects for coordination, persistent state, RPC, alarms, and WebSocket connections.
When should I avoid Durable Objects?
They are not intended for stateless request handling, maximum global distribution, or high fan-out independent requests.
Source text
SKILL.md · Apache-2.0
---
name: durable-objects
description: Build, debug, or review Cloudflare Durable Objects code for persistent state and coordination.
---
# 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.
| Resource | URL |
|----------|-----|
| Docs | https://developers.cloudflare.com/durable-objects/index.md |
| API Reference | https://developers.cloudflare.com/durable-objects/api/index.md |
| Best Practices | https://developers.cloudflare.com/durable-objects/best-practices/index.md |
| Examples | https://developers.cloudflare.com/durable-objects/examples/index.md |
| Roles and permissions | https://developers.cloudflare.com/workers/authorization/durable-objects/index.md |
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](./references/testing.md) - 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
| Need | Example |
|------|---------|
| Coordination | Chat rooms, multiplayer games, collaborative docs |
| Strong consistency | Inventory, booking systems, turn-based games |
| Per-entity storage | Multi-tenant SaaS, per-user data |
| Persistent connections | WebSockets, real-time notifications |
| Scheduled work per entity | Subscription 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
## Authorization
Durable Objects do not have separate roles or permissions; access follows the Worker that implements them. Retrieve the current [Durable Objects authorization guidance](https://developers.cloudflare.com/workers/authorization/durable-objects/index.md) before granting observability or Data Studio access, and scope the Workers role to the intended Worker or Workers product.
## 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 cases
const stub = env.MY_DO.getByName("room-123");
// From existing ID string
const id = env.MY_DO.idFromString(storedIdString);
const stub = env.MY_DO.get(id);
// New unique ID - store mapping externally
const 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);
// Handler
async alarm(): Promise<void> {
// Process scheduled work
// Optionally reschedule: await this.ctx.storage.setAlarm(...)
}
// Cancel
await this.ctx.storage.deleteAlarm();
```
## Testing
Read the [testing reference](./references/testing.md) before configuring a suite or writing Durable Object tests. It routes to current setup, APIs, and examples and identifies the behavior to cover.
© cloudflare · Apache-2.0 · cloudflare/skills