3.11. Workflows

In this chapter, you’ll learn about workflows and how to define and execute them.

What is a Workflow?#

A workflow is a series of queries and actions that complete a task.

You construct a workflow similar to how you create a JavaScript function, but unlike regular functions, a workflow creates an internal representation of your steps. This makes it possible to keep track of your workflow’s progress, automatically retry failing steps, and roll back steps.


How to Create and Execute a Workflow?#

1. Create the Steps#

A workflow is made of a series of steps. A step is created using the createStep utility function imported from @medusajs/workflows-sdk.

Create the file src/workflows/hello-world.ts with the following content:

src/workflows/hello-world.ts
1import { createStep, StepResponse } from "@medusajs/workflows-sdk"2
3const step1 = createStep("step-1", async () => {4  return new StepResponse(`Hello from step one!`)5})

This creates one step that returns a hello message.

Steps can accept input parameters.

For example, add the following to src/workflows/hello-world.ts:

src/workflows/hello-world.ts
1type WorkflowInput = {2  name: string3}4
5const step2 = createStep("step-2", async ({ name }: WorkflowInput) => {6  return new StepResponse(`Hello ${name} from step two!`)7})

2. Create a Workflow#

Next, add the following to the same file to create the workflow using the createWorkflow function:

src/workflows/hello-world.ts
1import {2  // other imports...3  createWorkflow,4} from "@medusajs/workflows-sdk"5
6// ...7
8type WorkflowOutput = {9  message: string10}11
12const myWorkflow = createWorkflow<WorkflowInput, WorkflowOutput>(13  "hello-world",14  function (input) {15    const str1 = step1()16    // to pass input17    const str2 = step2(input)18
19    return {20      message: str1,21    }22  }23)24
25export default myWorkflow

This creates a hello-world workflow. When you create a workflow, it’s constructed but not executed yet.

3. Execute the Workflow#

You can execute a workflow from different resources within Medusa.

  • Use API routes to execute the workflow in response to an API request or a webhook.
  • Use subscribers to execute a workflow when an event is triggered.
  • Use scheduled jobs to execute a workflow on a regular schedule.

To execute the workflow, invoke it passing the Medusa container as a parameter. Then, use its run method:

4. Test Workflow#

To test out your workflow, start your Medusa application:

Then, send a GET request to /store/workflow:

curl http://localhost:9000/store/workflow

You’ll receive the following response:

1{2  "message": "Hello from step one!"3}

When to Use Workflows#

Use workflows when
  • You're defining a flow with interactions across multiple systems and services.
  • You're defining flows to be used across different resources. For example, if you want to invoke the flow manually through an API Router, but also want to automate its running through a scheduled job.
  • You want to define configurations related to errors and how to roll-back steps. This is explained more in later chapters.

Resolve Resources#

Each step in the workflow receives as a second parameter a context object. The object holds a container property which is the Medusa container. Use it to resolve other resources, such as services, of your Medusa application.

For example:

src/workflows/product-count.ts
11}12
13const step1 = createStep("step-1", async (_, context) => {14  const productModuleService: IProductModuleService =15    context.container.resolve(ModuleRegistrationName.PRODUCT)16
17  const [, count] = await productModuleService.listAndCountProducts()18
19  return new StepResponse(count)20})21
22const myWorkflow = createWorkflow<unknown, WorkflowOutput>(23  "product-count",24  function () {25    const count = step1()26
27    return {28      count,29    }30  }31)32
33export default myWorkflow

In the step, you resolve the Product Module's main service and use it to retrieve the product count.

Was this chapter helpful?