Configuration

Durable Objects in cloudflare.config.ts

Declare the exported class and its storage, then bind to that class. A Durable Object needs both a lifecycle declaration and application code.

Beta tooling changes quickly. Examples are checked against cf 1.0.0-beta.5 and @cloudflare/config 0.20.0. See the sources below.

Quick configuration

cloudflare.config.ts
import { bindings, defineConfig, exports } from "cf/config";

export default defineConfig({
  worker: {
    name: "counter-worker",
    compatibilityDate: "2026-09-29",
    entrypoint: "./src/index.ts",
    exports: {
      Counter: exports.durableObject({ storage: "sqlite" }),
    },
    env: {
      COUNTERS: bindings.durableObject({
        worker: "counter-worker",
        exportName: "Counter",
      }),
    },
  },
});

This declares a new SQLite-backed class named Counter and gives the same Worker a COUNTERS binding. The Worker name in the binding matches the Worker that exports the class.

Two declarations, two purposes

worker.exports.Counter describes the class’s storage and deployment lifecycle. worker.env.COUNTERS connects application code to the class namespace. Neither declaration implements the class itself.

The current helper takes exportName; do not copy Wrangler’s class_name into it. Use the config builder to generate both declarations together for a new class.

Export the class from your source

src/index.ts
import { DurableObject } from "cloudflare:workers";

export class Counter extends DurableObject {
  async increment(): Promise<number> {
    const count = (await this.ctx.storage.get<number>("count") ?? 0) + 1;
    await this.ctx.storage.put("count", count);
    return count;
  }
}

export default {
  async fetch(_request: Request, env: {
    COUNTERS: DurableObjectNamespace<Counter>;
  }) {
    const stub = env.COUNTERS.getByName("shared-counter");
    const count = await stub.increment();
    return Response.json({ count });
  },
};

Generate the Cloudflare runtime types in your Worker project. This minimal example uses one named object; choose object identities around your application’s isolation needs.

Migrating an existing class

The new exports model can describe class creation, deletion, renaming and transfer. Existing state must be preserved intentionally. Do not turn every old class into a newly declared class or change its storage backend merely because the example uses SQLite.

Use cf migrate and review the class name, owning Worker, storage and lifecycle against the original configuration. Consult the official class export documentation before a rename or transfer.

Common mistakes

  • Adding only the binding and omitting the exported class declaration.
  • Declaring Counter while the source exports a differently named class.
  • Referencing another Worker unintentionally through the binding’s worker field.
  • Treating storage backend changes as a harmless configuration rename.

Read the configuration guide for binding structure or the KV comparison when deciding whether your state needs coordination.

Sources & verification

Cloudflare configuration types and helpersDurable Object class exports and migrationscf CLI source and README