Skip to main content

Workflows

Workflows are Medusa’s orchestration engine for building reliable, distributed transactions with automatic compensation (rollback). They compose multiple steps into a single, fault-tolerant operation.

Why Workflows?

Workflows solve critical challenges in distributed commerce systems:
  • Automatic rollback - Failed steps trigger compensation functions
  • Idempotency - Steps can be safely retried
  • Composability - Reuse steps across multiple workflows
  • Observability - Track execution state and errors
  • Background execution - Async steps for long-running operations
Workflows are the recommended way to implement business logic that spans multiple modules or requires transactional guarantees.

Creating a Step

Steps are the building blocks of workflows. Each step defines an action and optional compensation.

Basic Step Pattern

Source: packages/core/core-flows/src/api-key/steps/create-api-keys.ts:33-52

Step Response

The StepResponse constructor accepts two arguments:
  1. Output - Data returned to the workflow
  2. Compensation data - Data passed to the compensation function
Only include the minimum data needed for compensation (typically IDs). The compensation function receives this data, not the full output.

Step Context

Steps receive a context object with:
  • container - Dependency injection container
  • context - Shared context (transaction metadata, user info)
  • transactionId - Unique transaction identifier
  • idempotencyKey - For idempotent execution

Creating a Workflow

Workflows compose steps into a transaction with automatic compensation.

Basic Workflow Pattern

Source: packages/core/core-flows/src/api-key/workflows/create-api-keys.ts:51-64

Executing Workflows

Workflows are executed by calling them with a container and running:

Workflow Composition

Transform Data

Use transform to manipulate step outputs:
Source: packages/core/workflows-sdk/src/utils/composer/transform.ts:34-58
You cannot directly manipulate data in the workflow function. Always use transform to access runtime values.

Parallel Execution

Use parallelize to run steps concurrently:
Source: packages/core/workflows-sdk/src/utils/composer/parallelize.ts:11-42

Conditional Execution

Use when-then for conditional step execution:
Source: packages/core/workflows-sdk/src/utils/composer/when.ts:31-62
You cannot use regular if statements in workflows because they evaluate at composition time, not runtime. Use when-then instead.

Workflow Hooks

Hooks emit events at specific points in workflow execution:
Subscribe to hooks:

Async Steps

Steps can be marked as async for background execution:
Async steps require a workflow engine module (Redis or in-memory) to be configured. They’re ideal for operations like sending emails, processing images, or external API calls.

Compensation Flow

When a step fails, all previous steps are compensated in reverse order:
1

Step 1 executes

Creates a product → Returns product.id as compensation data
2

Step 2 executes

Creates prices → Returns price.ids as compensation data
3

Step 3 fails

Fails to attach to sales channel → Triggers compensation
4

Step 2 compensates

Deletes prices using price.ids
5

Step 1 compensates

Deletes product using product.id

Running Workflows as Steps

Workflows can be composed as steps in other workflows:
Source: packages/core/workflows-sdk/src/utils/composer/create-workflow.ts:203-296

Best Practices

Keep Steps Focused

Each step should do one thing. Split complex operations into multiple steps.

Always Provide Compensation

Every step that changes state should have a compensation function.

Minimize Compensation Data

Only pass IDs or minimal data needed to rollback.

Use Transform for Data Shaping

Don’t manipulate data directly in the workflow function.

Next Steps

Events

Learn how to emit and subscribe to events

Services

Build services that power your workflow steps