Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions docs/content/docs/deploying/world/cloudflare-world.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just left similar comments on a different community world PR - we need better explanation in the docs but essentially

for community worlds, the docs don't come from a markdown on our site. we currently simply link out to your readme and that's all automatically generated from the worlds-manifest

you can see an example of how the community world will look (https://useworkflow.dev/worlds/redis). This way you can keep the docs upto date on your README easily.

so adding to the worlds-manifest is enough to be added to the list. Additionally, we can setup e2e testing and benchmarking here so that those results are tracked and published to the docs site

the ones like surreal/redis/etc. all run inside github CI environment. but for cloudflare, I suppose we will need to run your world on a cf account we control for.

Let's get this added to the manifest first in this PR (please remove the docs changes - just the manifest) and I'll figure out the CI environment/setup soon after by following your README so we can start tracking and reporting it :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can copy the jazz example from manifest where we also only list it rn but don't have a CI env setup yet for it - preview

title: Cloudflare Workers World
description: Community world using Durable Objects, D1, and Cloudflare Queues.
type: integration
summary: Deploy workflows to Cloudflare Workers using Durable Objects for state, D1 for indexing, and Queues for dispatch.
prerequisites:
- /docs/deploying
related:
- /docs/deploying/world/local-world
- /docs/deploying/world/vercel-world
- /docs/deploying/world/postgres-world
---

The Cloudflare Workers World is a community-maintained backend that runs workflows on [Cloudflare's edge network](https://workers.cloudflare.com). It uses three Cloudflare primitives for a fully serverless architecture:

- **Durable Objects** for per-run state (events, steps, hooks, waits, streams)
- **D1 (SQLite)** for cross-run index queries
- **Cloudflare Queues** for reliable message dispatch

<Callout type="info">
This is a community World maintained at [`@ataylorme/workflow-world-cloudflare`](https://github.com/ataylorme/workflow-world-cloudflare). For issues and contributions, visit the [GitHub repository](https://github.com/ataylorme/workflow-world-cloudflare).
</Callout>

## Installation

Install the package:

```package-install
@ataylorme/workflow-world-cloudflare
```

## Cloudflare Bindings

Configure your `wrangler.toml` with the required bindings:

```toml title="wrangler.toml"
name = "my-workflow-worker"
main = "src/worker.ts"
compatibility_date = "2024-12-01"

[durable_objects]
bindings = [
{ name = "WORKFLOW_RUNS", class_name = "WorkflowRunDO" }
]

[[d1_databases]]
binding = "WORKFLOW_DB"
database_name = "workflow"
database_id = "<your-d1-database-id>"

[[queues.producers]]
binding = "WORKFLOW_QUEUE"
queue = "workflow-jobs"

[[queues.consumers]]
queue = "workflow-jobs"
max_batch_size = 10
max_retries = 3

[[migrations]]
tag = "v1"
new_classes = ["WorkflowRunDO"]
```

## Database Migration

Run the D1 migration to create index tables. This is idempotent and safe to run multiple times:

```ts
import { migrate } from '@ataylorme/workflow-world-cloudflare/d1';

await migrate(env.WORKFLOW_DB);
```

## Usage

Create the world in your Worker and re-export the Durable Object class:

```ts title="src/worker.ts" lineNumbers
import { createWorld, WorkflowRunDO } from '@ataylorme/workflow-world-cloudflare';

// Re-export the DO class so Cloudflare can instantiate it
export { WorkflowRunDO };

export default {
async fetch(request, env) {
const world = createWorld({
db: env.WORKFLOW_DB,
runs: env.WORKFLOW_RUNS,
queue: env.WORKFLOW_QUEUE,
});
// Use world with your workflow runtime...
},

async queue(batch, env) {
const world = createWorld({
db: env.WORKFLOW_DB,
runs: env.WORKFLOW_RUNS,
queue: env.WORKFLOW_QUEUE,
});
await world.handleQueueBatch(batch);
},
};
```

## How It Works

Each workflow run maps 1:1 to a Durable Object instance. All per-run state lives in the DO's transactional storage, which provides strong consistency without external databases.

D1 maintains a lightweight global index so that cross-run queries (`runs.list`, `hooks.getByToken`) work without needing to fan out to every DO. The DO writes index updates to D1 fire-and-forget after each mutation.

Workflow and step invocations are dispatched through Cloudflare Queues for reliable, at-least-once delivery.

## Limitations

- **`events.listByCorrelationId()`** — Requires `runId` context; the DO-per-run architecture cannot query across runs without knowing which DO to target
- **`steps.get()`** — Requires `runId` for the same routing reason
- **`readFromStream()`** — Expects stream names in `runId:streamName` format because the Streamer interface does not pass `runId` for reads
- **Cloudflare platform** — Requires Cloudflare Workers with Durable Objects, D1, and Queues enabled

For local development, use the [Local World](/worlds/local) which requires no external services.
2 changes: 1 addition & 1 deletion docs/content/docs/deploying/world/meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"title": "World",
"pages": ["local-world", "vercel-world", "postgres-world"]
"pages": ["local-world", "vercel-world", "postgres-world", "cloudflare-world"]
}
14 changes: 14 additions & 0 deletions worlds-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@
"services": [],
"requiresCredentials": true,
"credentialsNote": "Requires JAZZ_API_KEY, JAZZ_WORKER_ACCOUNT, and JAZZ_WORKER_SECRET from Jazz Cloud"
},
{
"id": "cloudflare",
"type": "community",
"package": "@ataylorme/workflow-world-cloudflare",
"name": "Cloudflare Workers",
"description": "Cloudflare Workers world using Durable Objects for per-run state, D1 for cross-run queries, and Cloudflare Queues for message dispatch",
"repository": "https://github.com/ataylorme/workflow-world-cloudflare",
"docs": "/docs/deploying/world/cloudflare-world",
"features": [],
"env": {
"WORKFLOW_TARGET_WORLD": "@ataylorme/workflow-world-cloudflare"
},
"services": []
}
]
}
Loading