Skip to content
GitHubXDiscordRSS

Durable Object

This guide explains how to create, bind and use Cloudflare Durable Objects within your Worker scripts.

  1. Create a Durable Object

    At a bare minimum, you need to create a DurableObjectNamespace object as a stable reference to your Durable Object namespace.

    import { DurableObjectNamespace } from "alchemy/cloudflare";
    const counter = DurableObjectNamespace("counter", {
    className: "Counter",
    // whether you want a sqllite db per DO (usually yes!)
    sqlite: true,
    });
  2. Bind to a Worker

    Then bind it to your Worker:

    export const worker = await Worker("Worker", {
    name: "my-worker",
    entrypoint: "./index.ts"
    bindings: {
    // bind the Durable Object namespace to your Worker
    COUNTER: counter,
    },
    });
  3. Implement the Durable Object Class

    To use this Durable Object, our Worker script must include a class for the Durable Object and then some code in the fetch handler to interact with it.

    import type { worker } from "./alchemy.run";
    import { DurableObject } from "cloudflare:workers";
    export class Counter extends DurableObject {
    declare env: typeof worker.Env;
    private count: number;
    constructor(ctx: DurableObjectState, env: typeof worker.Env) {
    super(ctx, env);
    // Initialize count from storage or 0
    this.count = Number(this.ctx.storage.kv.get('count') || 0);
    }
    async fetch(request: Request) {
    const url = new URL(request.url);
    const path = url.pathname;
    if (path === "/increment") {
    this.count++;
    } else if (path === "/decrement") {
    this.count--;
    }
    // Update count in storage
    this.ctx.storage.kv.put('count', this.count.toString());
    return Response.json({ count: this.count });
    }
    }
  4. Call from a Worker

    Now, our fetch handler can get a Durable Object instance via the COUNTER binding:

    import { env } from "cloudflare:workers";
    export default {
    async fetch(request: Request) {
    const url = new URL(request.url);
    // Create an ID for the Counter (different IDs = different Counter instances)
    const id = env.COUNTER.idFromName("A");
    // Get a stub for the Counter instance
    const stub = env.COUNTER.get(id);
    // Forward the request to the Durable Object
    return stub.fetch(request);
    },
    };
  5. (Optional) Rename the Class

    Alchemy takes care of migrations automatically when you rename the class name.

    import { DurableObjectNamespace } from "alchemy/cloudflare";
    const counter = DurableObjectNamespace("counter", {
    className: "Counter",
    className: "MyCounter",
    // whether you want a sqllite db per DO (usually yes!)
    sqlite: true,
    });