To migrate from Cloudflare Workflows to Vercel Workflows, rewrite your WorkflowEntrypoint class as a function marked 'use workflow', move each step.do() callback into its own 'use step' function, replace step.sleep() with sleep(), translate event waits into hooks or webhooks, and start runs with start() from server-side code.
Both platforms run durable, resumable functions, but their APIs differ in shape. Treat the migration as a semantic translation, not a one-to-one port: some constructs map directly, others need a different pattern, and a few need a redesign.
Copy link to headingOverview
- Map each Cloudflare Workflows construct to its Vercel Workflows equivalent
- Rewrite entrypoint classes, steps, and triggers in the Workflow SDK's format
- Translate
step.waitForEvent()andsendEvent()interactions to one hook or webhook resume surface - Recreate rollback behavior with explicit compensation
- Verify migrated runs in the Vercel dashboard
Copy link to headingConcept and API mapping
How do Cloudflare Workflows concepts map to Vercel Workflows?
Vercel Workflows builds on the Workflow SDK, which uses two directives, 'use workflow' and 'use step', to turn ordinary async functions into durable workflows. There is no base class to extend and no step context object to thread through your code.
| Cloudflare Workflows concept/API | Vercel Workflows equivalent or migration approach | Migration notes |
|---|---|---|
WorkflowEntrypoint class with run(event, step) | An async function marked 'use workflow' | The function body replaces run(). Function parameters replace the event payload. |
step.do() | A separate async function marked 'use step' | Each step compiles into an isolated route and retries automatically on failure. |
step.sleep() | sleep() from the workflow package | Call it inside the workflow function. The run consumes no compute while paused. |
step.waitForEvent() and sendEvent() | Exactly one resume surface: createHook() with resumeHook(), or createWebhook() | Pick one surface per event interaction. See the event migration section below. |
| Starting a workflow through a binding | start(workflow, [args]) from workflow/api | Call it from server-side code such as a route handler. |
| Bindings and service integrations | Environment variables and provider SDKs inside steps | Migrate each binding separately. Keep all side effects in 'use step' functions. |
| Rollback logic | Explicit compensation in the workflow | Track completed work and undo it in reverse order when a later step throws. |
| Workflow observability | Workflows in the Vercel dashboard | Every step, input, output, sleep, and error is recorded automatically. |
Work through the table row by row for each workflow before touching code. Direct rows like sleeps and steps translate mechanically. The rows for event waits, bindings, and rollback logic drive most of the migration effort, and the sections below cover each of them in sequence.
Copy link to headingWhat doesn't map
This guide does not map step.sleepUntil(), per-step retry and backoff configuration, caller-supplied instance IDs, createBatch(), or instance lifecycle controls. It also does not cover automatic rollback handlers (compensation on Vercel Workflows is code you write) or moving in-flight instances between platforms. For these, check the current Workflow SDK reference before planning, redesign around the primitives in the table above, and let running Cloudflare instances finish before cutover.
Copy link to headingMigration procedure
Copy link to heading1. Install the Workflow SDK
Add the workflow package to your project:
pnpm reports the packages it added and lists workflow under dependencies with the version it resolved.
The SDK is open source. The vercel/workflow repository carries the source, the API surface, and migration reference material.
Copy link to heading2. Rewrite the entrypoint as a workflow function
Replace the WorkflowEntrypoint class with an exported async function marked 'use workflow'. Parameters you read from the event payload become function arguments:
step.sleep() calls become sleep() calls directly in the workflow body. The imported reserveInventory and chargePayment functions are the step functions you write next.
Copy link to heading3. Move side effects into step functions
Each step.do() callback becomes its own function marked 'use step'. API calls, database writes, and other side effects belong here, not in the workflow body:
Steps retry automatically on transient failures, so throw on errors rather than swallowing them.
Copy link to heading4. Start runs from server-side code
Cloudflare starts instances through a workflow binding on the environment. On Vercel, import start from workflow/api and call it from a route handler, server action, or other server-side code:
The response confirms that the run started and provides an ID for later lookup.
Copy link to heading5. Replace bindings and platform integrations
Workflow code that read Cloudflare bindings needs those resources replaced individually: storage, queues, and secrets each move on their own track.
The guide to migrating from Cloudflare to Vercel covers the platform-level pieces. If the surrounding app is a TanStack Start project, follow the TanStack Start migration guide for the framework move. Teams deciding where the app itself should run can compare the platforms in Next.js on Vercel vs Cloudflare.
Copy link to heading6. Deploy and verify
Deploy the project, trigger a test run, then open your Vercel dashboard, select the project, and go to Workflows. Confirm each migrated workflow appears, its steps complete in order, and sleeps and event waits suspend and resume as expected.
Copy link to headingEvent-driven workflow migration
Cloudflare workflows pause with step.waitForEvent() and resume when something calls sendEvent() on the instance.
Vercel Workflows resumes paused runs through hooks and webhooks, and each translated event interaction should use exactly one resume surface, a rule the SDK's own shared migration patterns spells out:
- Use
createHook()in the workflow andresumeHook()from your server code when your own app resumes the run and you can address it with a deterministic token such asorder:${orderId}:approval. - Use
createWebhook()when an external system needs a generated callback URL to resume the run.
The waitForEvent() call that your own backend resolved translates to a hook:
The route handler that replaces the sendEvent() call resumes the run by token:
Don't pair createWebhook() with resumeHook(), and don't build a custom callback route when the generated webhook.url is the intended resume surface. For a complete event-driven example, the guide to building stateful Slack bots with Vercel Workflows pauses on user input and resumes from Slack events.
Copy link to headingReliability and operational migration
Cloudflare rollback logic becomes explicit compensation on Vercel Workflows. Track undo actions as steps complete, and run them in reverse order:
The compensation functions live in the same steps file as the work they undo. Because they are 'use step' functions, they get the same durability:
Two operational notes for cutover. First, external writes should be idempotent: pass getStepMetadata().stepId as an idempotency key so a retried step doesn't double-charge or double-send. Second, capacity assumptions from Cloudflare don't carry over. Review Workflows pricing and limits for current quotas and billing dimensions instead of copying numbers from your old configuration.
Copy link to headingFAQ
Copy link to headingCan I run my Cloudflare Workflows code on Vercel Workflows without changes?
No. Cloudflare Workflows uses a WorkflowEntrypoint class and a step context object, while Vercel Workflows uses 'use workflow' and 'use step' directives on plain async functions. The durable-execution concepts carry over, but every entrypoint, step, trigger, and event wait needs rewriting.
Copy link to headingHow do I replace step.waitForEvent() and sendEvent() in Vercel Workflows?
Choose exactly one resume surface per event interaction. Use createHook() in the workflow with resumeHook() in your server code when your own app resumes the run with a deterministic token. Use createWebhook() when an external system needs a generated callback URL.
Copy link to headingDo Vercel Workflows steps retry automatically?
Yes. Functions marked 'use step' get built-in retries and survive failures like network errors or process crashes. Cloudflare's per-step retry and backoff configuration does not translate one-to-one, so review retry behavior in the Workflow SDK reference before relying on specific retry counts or delays.
Copy link to headingCan I migrate in-flight Cloudflare Workflows instances to Vercel Workflows?
This guide does not provide a method to migrate in-flight Cloudflare Workflows instances. Plan a cutover that lets existing Cloudflare instances drain before directing new starts to Vercel Workflows.
Copy link to headingWhere do I monitor migrated workflows on Vercel?
In the Vercel dashboard, select your project and go to Observability, then Workflows. Every step, input, output, sleep, and error is recorded automatically, so you can trace a run end to end without adding instrumentation.