Workflows are a Medusa framework primitive. This page focuses on the constraints and conventions that trip people, and agents, up.
The composition function is not normal JavaScript
The function you pass tocreateWorkflow is a composition function. It runs once at build time to wire steps together. It does not execute your business logic at request time. Because of that, it has hard constraints.
Anything that looks like normal logic goes into a step (for side effects) or a transform (for shaping data between steps):
src/workflows/create-brands.ts
One mutation per step and compensation
A step is the unit of work and the unit of rollback. The rule: each step performs a single mutation and defines how to undo it.createStep takes an invoke function and a compensation function. The invoke returns a StepResponse whose second argument is the data the compensation needs.
src/workflows/steps/create-brands.ts
createBrands above is undone by deleteBrands. Splitting mutations one per step is what makes this reliable: a step that does two writes can only half-compensate.
Reuse built-in steps
Don’t hand-roll what the framework already ships. Medusa’score-flows exports composable steps you should reuse instead of writing your own:
Hooks let others extend your workflow
Expose extension points withcreateHook so consumers can inject behaviour such as validation or side effects without forking the workflow. Add a validate hook before the mutation and a brandsCreated hook after it:
The query engine
Reads inside a step, and anywhere else, go through Query, the graph engine that resolves data across modules and links. Resolve it from the container and callquery.graph:
Checklist for a workflow
- Composition function is a named
function, with noasync/await,if, loops,try/catch,new Date(), or step-output property access. - Data shaping between steps uses
transform; conditional steps usewhen. - Each step does exactly one mutation and defines a compensation function.
StepResponsepasses the compensation the data it needs to undo the work.- Built-in steps (
createRemoteLinkStep,emitEventStep) andrunAsStepare reused instead of reimplemented. - Reads use
query.graph; no cross-module service calls. - Extension points are exposed as hooks, not by forking.
Next steps
Extend a workflow
Register handlers on a workflow’s hooks to add behaviour without forking.
Best practices overview
See how workflows fit the wider Mercur architecture.