Use Case
Our workflow will:- Receive a list of steps to execute
- Execute each step in order, one by one
- Persist step results between requests
- Support multiple workflow versions with different step orders
- Ensure workflows do not break when retried or resumed
- Customers want dynamic workflows with different type of steps and ordering
- Workflow logic is driven by configuration
- You need safe retries, resumes, and idempotency
Code Example
Code Breakdown
1. Dynamic Step Configuration
Instead of hardcoding the workflow, we accept a list of step names from the request payload.- Run X:
AddOne → MultiplyWithTwo - Run Y:
MultiplyWithTwo → AddOne → AddOne - Run Z:
AddOne
Instead of passing the step list in the request payload, you can store it somewhere else and fetch it inside the workflow as well.
2. Executing Steps One by One
At first glance, thefor loop looks like a normal synchronous loop. However, in Upstash Workflow, each iteration of the loop (in other terms, every step) is executed across multiple HTTP requests, not in a single function invocation.
- The workflow endpoint is called with the initial payload.
- The loop starts at
i = 0. context.run("step-0:AddOne")is encountered.- Since this step has never run before, Upstash executes the function body.
- The result is stored in durable state.
- The HTTP request ends immediately after this step completes.
- Upstash triggers the workflow endpoint again.
- The request payload now includes the result of
step-0. - The loop runs again from the beginning.
context.run("step-0:AddOne")is encountered, but it is skipped because it already exists in state.- The loop continues to
i = 1. context.run("step-1:MultiplyWithTwo")executes.- The result is persisted, and the request ends.
- This process repeats until every step in the loop has been executed exactly once.
- Each iteration of the loop corresponds to a separate HTTP execution.
context.run call so the workflow engine can:
- Resume execution safely
- Skip completed work
- Retry failed steps independently
- Guarantee exactly-once execution semantics
context.run, the engine cannot resume partway through that logic.
3. Step Naming and Ordering
Upstash Workflow identifies steps using:- The order of
context.runcalls - The step name passed to
context.run
- Step names must not change between retries
- Step order must remain the same
4. Versioning Workflows Safely
If you want to change:- Step order
- Step names
- Number of steps
- Keep old versions immutable
- Route versions inside the same endpoint if needed
- Ensure each version always executes the same flow
version = v1→AddOne → MultiplyWithTwoversion = v2→MultiplyWithTwo → AddOne
5. How the Step Result Resolve Mechanism Works
Behind the scenes, the workflow endpoint is called multiple times. On each request:- The request contains the initial payload
- Plus results of already executed steps
- The engine determines which step is next
- Only the next step is executed
6. Common Pitfalls
Avoid the following:- ❌ Running multiple logical steps inside a single
context.run - ❌ Changing step names and order between executions
- ❌ Conditional execution based on non-deterministic logic (
Math.random,Date.now)