Skip to content

Durable Objects

Durable Objects bind compute and strongly consistent storage to one object. On this platform every object lives on the single local workerd process.

For example, you can use Durable Objects for:

  • Coordinating state among multiple clients
  • Strongly consistent per-object storage
  • Alarms and WebSocket hibernation
ts
export class Counter {
  constructor(private readonly ctx: DurableObjectState, private readonly env: Env) {}
  async fetch(request: Request): Promise<Response> {
    const n = ((await this.ctx.storage.get<number>("n")) ?? 0) + 1;
    await this.ctx.storage.put("n", n);
    return Response.json({ n });
  }
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const id = env.COUNTER.idFromName("global");
    return env.COUNTER.get(id).fetch(request);
  },
} satisfies ExportedHandler<{ COUNTER: DurableObjectNamespace }>;

Bind in open-compute.json. Durable Object bindings require className:

json
{
  "name": "do-app",
  "main": "src/index.ts",
  "bindings": {
    "COUNTER": { "type": "do_namespace", "id": "<do-namespace-id>", "className": "Counter" }
  }
}

className only checks class semantics in generated framework config. It is not sent as the resource id. Grammar: bindings. The CLI is oc / oc run / oc types.

Compatibility

TopicCloudflareopen-compute
Worker / class APIDurable Objects APISame: namespace idFromName / newUniqueId / idFromString / get / getByName, stub fetch / RPC, state.storage KV and SQL, transactions, output gate
PlacementGeographic scheduling, locationHint / jurisdiction / migrationAll objects on one local workerd; locationHint / jurisdiction / migration have no geo effect
AlarmsAvailable7 methods supported: getAlarm / setAlarm / deleteAlarm and the alarm() handler
HibernationAvailableSupported
Bindingwrangler durable_objects{ type, id, className }; className required
Fetcher.connect()General outboundDeclared capability tunnel

Next