This is an experimental Cloudflare-focused fork that hosts the runtime (
workflow-cloudflare-world), the app bindings (workflow-cloudflare-bindings), and the SvelteKit demo workbench. It is not the upstream Workflow DevKit repo. For official docs visit useworkflow.dev.
packages/world-cloudflare: the deployable Cloudflare world that uses D1, Queues, R2, Durable Objects, and Cloudflare Containers to execute workflows off-app.packages/workflow-cloudflare-bindings: the client/bindings package that rewrites workflow handlers and forwardsworkflow/apicalls to the remote runtime.workbench/svelte-cf: a SvelteKit + Workers starter wired to the bindings package and Wrangler service bindings.problems.md: running RFC / issue log describing current blockers (notably the Vite transformer gap).
Everything else in this repo exists only to support the Cloudflare world experiments.
-
Scaffold and deploy the runtime:
npx workflow-cloudflare-world init my-workflow-runtime cd my-workflow-runtime pnpm install wrangler d1 create <db-name> wrangler d1 migrations apply <db-name> wrangler deploy
The CLI drops
wrangler.toml, Dockerfile + container config, and the initial D1 migration so the worker/runtime can run queues, streams, and containers out of the box. -
Connect your app (e.g., SvelteKit Worker):
pnpm add workflow-cloudflare-bindings
// vite.config.ts import { cloudflareWorkflowTransformer } from 'workflow-cloudflare-bindings/vite-plugin'; export default defineConfig({ plugins: [ cloudflareWorkflowTransformer(), sveltekit(), ], });
[[services]] binding = "WORKFLOW_RUNTIME" service = "my-workflow-runtime"
// hooks.server.ts (SvelteKit) or Worker entry import { setupGlobalContainerClient } from 'workflow-cloudflare-bindings'; export const handle = async ({ event, resolve }) => { setupGlobalContainerClient(event.platform?.env); return resolve(event); };
With the binding set, calls to
workflow/apiare proxied to the containerized executor running in your Cloudflare account.
- Queues:
WORKFLOW_QUEUEhandles workflow jobs,STEP_QUEUEhandles step retries.handleQueueMessagedispatches workflow jobs to the container executor via service binding or HTTPS, while step jobs run directly in the Worker. - Storage: A D1 schema (see
packages/world-cloudflare/src/drizzle/schema.ts) persists runs, steps, events, and hooks. The CLI copies the base migration into new projects. - Streaming: A
StreamCoordinatorDurable Object fans out chunks to readers and persists them to R2. - Containers: Cloudflare Containers host the Workflow VM because Workers do not support
vm.runInContext, deterministic Math.random, or other sandbox requirements. The Worker queues jobs into the container viaWORKFLOW_EXECUTOR. - Bindings package: The Vite plugin swaps
workflow/runtimeimports with remote shims so Workers never bundle@workflow/world-local.setupGlobalContainerClientstores a singleton client that knows how to talk to the executor via service binding orWORKFLOW_EXECUTOR_URL.
For a deeper dive, read:
packages/world-cloudflare/README.mdpackages/workflow-cloudflare-bindings/README.mdpackages/world-cloudflare/HOW_IT_WORKS.md
This project is still in flux. The runtime + CLI + workbench deploy cleanly, but the bindings plugin must be updated to match modern SvelteKit output (see problems.md). Until that transformer lands, Workers may still bundle the local world and crash on Cloudflare.
Contributions, repro cases, and ideas are welcome via GitHub Discussions or issues in this repo. Please include Wrangler config, bindings, and .svelte-kit output snippets when reporting bugs.