Skip to main content
Experimental — APIs may change. Currently only supports Cloudflare Durable Objects as the execution engine.
This guide walks you through defining a simple order workflow, wiring it into a Cloudflare Worker, and triggering it with the WorkflowClient.
1

Install dependencies

Install @durable-effect/workflow and effect as dependencies.
npm install @durable-effect/workflow effect
2

Define your workflow

Create a file (e.g. src/workflows.ts) that defines your workflows and exports the Durable Object class and client.Workflows are built with Workflow.make(). Each step caches its result in Durable Object storage and replays on resume — so even if the worker restarts mid-execution, completed steps are not re-run.
import { Effect } from "effect";
import { Workflow, Backoff, createDurableWorkflows } from "@durable-effect/workflow";

const processOrderWorkflow = Workflow.make((orderId: string) =>
  Effect.gen(function* () {
    const order = yield* Workflow.step({
      name: "Fetch order",
      execute: fetchOrder(orderId),
    });
    yield* Workflow.sleep("3 seconds");

    yield* Workflow.step({
      name: "Process payment",
      execute: processPayment(order),
      retry: {
        maxAttempts: 5,
        delay: Backoff.exponential({ base: "1 second", max: "60 seconds" }),
      },
    });

    yield* Workflow.step({
      name: "Send confirmation",
      execute: sendEmail(order.email),
    });
  })
);

// Register all workflows in a record
const workflows = {
  processOrder: processOrderWorkflow,
} as const;

// createDurableWorkflows returns the DO class and a typed client
export const { Workflows, WorkflowClient } = createDurableWorkflows(workflows);
3

Export the Durable Object class from your worker entry point

Cloudflare needs the Workflows class to be a named export from your worker. In your main entry file (e.g. src/index.ts):
import { Workflows } from "./workflows";

// Export the Durable Object class
export { Workflows };

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Your fetch handler
  },
};
4

Configure wrangler.jsonc

Add the Durable Object binding and migration to your wrangler.jsonc:
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2025-11-28",

  "durable_objects": {
    "bindings": [
      {
        "name": "WORKFLOWS",
        "class_name": "Workflows"
      }
    ]
  },

  "migrations": [
    {
      "tag": "v1",
      "new_classes": ["Workflows"]
    }
  ]
}
5

Trigger the workflow with the WorkflowClient

Use WorkflowClient.fromBinding to get a typed client, then call runAsync to start a workflow instance.
import { Effect } from "effect";
import { WorkflowClient } from "./workflows";

// Inside your fetch handler or any Effect program:
Effect.gen(function* () {
  const client = WorkflowClient.fromBinding(env.WORKFLOWS);

  // Start a workflow asynchronously — returns immediately
  const { id } = yield* client.runAsync({
    workflow: "processOrder",
    input: orderId,
    execution: { id: orderId }, // Optional: use a custom execution ID
  });
});
You can also run imperatively outside of an Effect context:
const client = WorkflowClient.fromBinding(env.WORKFLOWS);

const { id } = await Effect.runPromise(
  client.runAsync({
    workflow: "processOrder",
    input: orderId,
    execution: { id: orderId },
  })
);

Next steps

Workflow steps

Learn how step caching, replay, and serialization work.

Durable sleep

Sleep for seconds, hours, or months — across restarts and deployments.

Retry & timeouts

Configure exponential backoff, jitter, and per-step timeouts.

WorkflowClient

Trigger, cancel, and inspect workflows with the type-safe client.

Build docs developers (and LLMs) love