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";
    export class Counter {
    declare env: typeof worker.Env;
    private count: number;
    constructor(state, env: typeof worker.Env) {
    this.state = state;
    this.count = 0;
    }
    async fetch(request) {
    const url = new URL(request.url);
    const path = url.pathname;
    // Retrieve current count
    this.count = (await this.state.storage.get("count")) || 0;
    if (path === "/increment") {
    this.count++;
    await this.state.storage.put("count", this.count);
    } else if (path === "/decrement") {
    this.count--;
    await this.state.storage.put("count", this.count);
    }
    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,
    });