Work that survives the reload.
Long-running jobs on Cloudflare Workflows. Every step checkpoints as it completes, so a run that dies halfway resumes from where it stopped instead of starting the whole thing over.
- Checkpointed steps
- Durable sleeps
- Human approval gates
- Cron schedules
The job outlives the request.
A Worker request dies in seconds. The work you actually care about — a transcode, a model run, an overnight report — does not fit in that window.
Steps that checkpoint
Each step's result is persisted the moment it finishes. When a run resumes, completed steps replay from storage instead of executing twice — so retrying is cheap and safe.
Sleep without holding anything open
A run can pause and let the platform wake it later. Nothing stays resident, nothing burns CPU while it waits, and the wake-up is exactly once.
Stop and ask a human
A run can block on an external event — an approval, a webhook, a click in your admin — and pick up the instant it arrives.
Kill it halfway. It comes back.
This is the demo task that ships with the engine: fetch, cool down, finalize. Reload the page mid-run and the completed steps stay completed — they are read back from storage, not re-executed.
- fetch-data donectx.step
- cool-down donectx.sleep · '2 seconds'
- finalize donectx.step
The dashboard mirrors every step, log line and status into D1 and polls for updates.
Every run is a page you can open.
This is the dashboard that ships with the engine, rebuilt here in HTML rather than screenshotted. Task registry on the left, every run and its status on the right — and each run drills down to steps, logs, payload and result.
| Status | Task | Run ID | Created |
|---|---|---|---|
| running | demo | 5b8f0d2e-9a41-4c7b-b1e6-3d92c04a7f15 | 7/17/2026, 9:42:07 AM |
| waiting | approval | e2c74d68-0b3f-4b1a-9e57-8a61f9d0c243 | 7/17/2026, 9:40:52 AM |
| complete | ticker | 9f31b7ac-6e05-4d92-8c48-527b0ae14d86 | 7/17/2026, 9:40:00 AM |
| complete | demo | 4a0de91b-7c56-4f38-a2d3-6b18e5c97f02 | 7/17/2026, 9:35:11 AM |
| errored | demo | c67a25f4-3d18-49ab-b590-e01c8f6b2a37 | 7/17/2026, 9:31:48 AM |
| complete | approval | 1d94e3b0-52c7-46fe-8b2a-90f4d7a6c518 | 7/16/2026, 6:03:29 PM |
{
"summary": "Deploy build #42 to production"
}Live, the boring way
The runs table polls every 2 seconds and an open run every 1.5 — no websocket to babysit. Status flips from running to complete while you watch.
A control plane, not a viewer
Cancel a stuck run, retry an errored one, or send a waiting run the event it is blocked on — every run is operable from the buttons in its own header.
Approvals are one click
A run suspended on ctx.waitForApproval shows Approve and Reject right in the header. It costs nothing while it waits; the decision lands and the next line runs.
Steps are just functions you name.
Wrap the parts you never want to repeat in a named step. Sleeps and waits are first-class. Trigger a run over HTTP with a bearer token, from the typed API, or straight across a Worker service binding.
defineTask<DemoPayload>('demo', {
async handler(payload, ctx) {
const count = payload?.items ?? 3;
await ctx.log('info', `demo task started for ${count} item(s)`);
// named step — its result is checkpointed
const fetched = await ctx.step('fetch-data', async () => ({
items: Array.from({ length: count }, (_, i) => ({ id: i + 1 })),
}));
// durable sleep — nothing stays resident
await ctx.sleep('cool-down', '2 seconds');
return ctx.step('finalize', async () => ({
total: fetched.items.length,
ok: true,
}));
},
});What the engine actually guarantees.
The boring parts are the ones you find out about at 3am, so here they are up front.
Big outputs spill to R2
A step result over 512 KiB is offloaded to object storage instead of slamming into the engine size limit.
Schedules at minute granularity
A cron trigger sweeps due schedules every minute and starts the runs that are ready.
Cancel, retry, resume
Every run is addressable from the control plane — terminate it, restart it, or send it the event it is waiting for.
Progress lands in D1
Steps, logs and status are mirrored into your database as the run advances, so the timeline survives the worker that produced it.
Triggers dedupe on a key
Send the same trigger twice with one idempotencyKey and you get one run — the key maps to a stable instance id that is created at most once.
Retries are per step, with backoff
Each step declares its own retry limit, delay and backoff curve — constant, linear or exponential — plus a timeout, forwarded straight to the engine.
Cloudflare Workflows · Hono on Workers · D1 for steps and logs · R2 for large outputs · cron-triggered schedules
Anything too slow for a request.
AI generation runs
A model call that takes minutes, chained into three more. Checkpoint each stage so a timeout costs you one step, not the whole pipeline.
Media and file processing
Fetch, transcode, upload, notify. Each stage records its own result, and a failed upload never re-runs the transcode.
Scheduled reports
A cron schedule kicks off the run; the run does the slow part on its own time and writes the result when it is ready.
Approval workflows
Do the work, then stop and wait for a human to say yes. The run sits there costing nothing until the event lands.
Tasks is pre-launch. The engine, dashboard and schedules run today, but it ships with demo task definitions and the source is not public yet. Task definitions live inside the server — there is no separate SDK package to install, and the dashboard polls rather than streaming.
Follow what we’re building.
We’ll only email you when we have a product update or industry news genuinely worth your attention. No inbox noise—only content that’s useful to you.