Skip to main content
Common distributed patterns are simple to implement in workflows and require learning no new syntax. You can just use familiar async/await patterns.

Sequential Execution

The simplest way to orchestrate steps is to execute them one after another, where each step can be dependent on the previous step.

Parallel Execution

When you need to execute multiple steps in parallel, you can use Promise.all to run them all at the same time.
This not only applies to steps - since sleep() and webhook are also just promises, we can await those in parallel too. We can also use Promise.race instead of Promise.all to stop executing promises after the first one completes.

A Full Example

Here’s a simplified example taken from the birthday card generator demo, to illustrate how sequential and parallel execution can be combined.

Timeout Pattern

A common requirement is adding timeouts to operations that might take too long. Use Promise.race with sleep() to implement this pattern.
This pattern works with any promise-returning operation including steps, hooks, and webhooks. For example, you can add a timeout to a webhook that waits for external input:

Workflow Composition

Workflows can call other workflows, enabling you to break complex processes into reusable building blocks. There are two approaches depending on your needs.

Direct Await (Flattening)

Call a child workflow directly using await. This “flattens” the child workflow into the parent - the child’s steps execute inline within the parent workflow’s context.
With direct await, the parent workflow waits for the child to complete before continuing. The child’s steps appear in the parent’s event log as if they were called directly from the parent.

Background Execution via Step

To run a child workflow independently without blocking the parent, use a step that calls start(). This launches the child workflow in the background.
With background execution, the parent workflow continues immediately after starting the child. The child workflow runs independently with its own event log and can be monitored separately using the returned runId. Choose direct await when:
  • The parent needs the child’s result before continuing
  • You want a single, unified event log
Choose background execution when:
  • The parent doesn’t need to wait for the result
  • You want separate workflow runs for observability