Work in many steps, carried to the end.
A run goes step by step and keeps each step's result. If a server fails or you deploy a new version, the run carries on from the last finished step, and a finished step never runs again.
What you get
In your own function
A function exports workflow(event, step, env, ctx) and writes each step with step.do. No server, queue or table to hold the run's state.
Retries for each step
A step that throws is retried on its own, with backoff and a timeout. Mark an error that is not worth retrying with NonRetryableError.
Sleeps of up to months
step.sleep and step.sleepUntil hold a run until the time you set, from seconds to months. Nothing runs meanwhile, and it costs nothing.
Wait for an event
step.waitForEvent holds a run until an event of a given type arrives, with the timeout you set. An event that arrives early is kept for the step that waits for it.
Talk to a running run
Send a run in progress a signal, query its state or update its data. Cancel it by hand or when an event arrives.
Parallel steps and child runs
Run several steps at once and wait for all of them, choose the next path from a step's result, or start another workflow from a run.
Undo finished work
If a step fails midway, compensating steps undo the earlier steps' work, such as refunding a charge. A run parked on a failure resumes from there once the cause is fixed.
Flow control
Concurrency per key, throttling and rate limits, debounce and batching of bursts, priority, and one run at a time per key, such as one customer.
Start from anywhere
Start a run from the API, the CLI, MCP or the dashboard, or let an event, a cron schedule, an HTTP request or a queue message start it.
Idempotent starts
Starting again with the same unique id returns that run and starts nothing new. Each step gets its own idempotency key too, so its outside work is not done twice.
Each run keeps its version
A run that has started finishes on the version of the code it started with, even if you deploy a new one while it runs.
A history of every run
A list of runs with each one's state, and for each run the history of its steps with their input, output, attempts and errors. Rerun a run from the step you choose.
Many steps, one function
Each step has a name and its result is kept. The run sleeps for an hour, waits up to a week for an approval, then carries on.
export default {
async workflow(event, step, env) {
const { order } = event.payload
const charge = await step.do("charge", ({ idempotencyKey }) =>
chargeCard(order, idempotencyKey))
await step.sleep("cool-off", "1h")
const approved = await step.waitForEvent("approval", { type: "approved", timeout: "7d" })
if (!approved) throw new step.NonRetryableError("not approved in time")
await step.do("ship", () => ship(order))
return { charge: charge.id }
},
}Per step
Each step that runs is counted. The time a run spends sleeping or waiting for an event costs nothing. Use comes from the month's credit first, then from the wallet.
Questions
The run carries on from the last finished step on another server. The finished steps' results are read back, and those steps do not run again.
Each step's result is recorded exactly once. But a step cut off before its result is recorded runs again, so each step gets its own idempotencyKey to pass to the service it calls.
A run is replayed from the start with its kept results, so code outside the steps must do the same thing every time. Read the time, random numbers and anything from outside inside a step.
Runs in progress finish on the version they started with. New runs start on the new version.
In a queue each message is a job on its own. A workflow is work in many steps whose state is kept, that can wait for days, and whose every step you can see. Use them together: a queue message can start a run.
In the dashboard, a run's history shows each step with its input, output, attempts and errors. You get the same from cloudhost workflows history, the API or MCP.
Write your first workflow
One function, a few steps, one command to start.
Sign-up is by invite for now. If you have a code, create your account.
Sign up withEmail codeSMS code