Workflows overview
Workflows let you define complex sequences of tasks using clear, structured steps rather than relying on the reasoning of a single agent. They give you full control over how tasks are broken down, how data moves between them, and what gets executed when.
When to use workflows
Use workflows for tasks that are clearly defined upfront and involve multiple steps with a specific execution order. They give you fine-grained control over how data flows and transforms between steps, and which primitives are called at each stage.
📹 Watch: → An introduction to workflows, and how they compare to agents YouTube (7 minutes)Â
Core principles
Mastra workflows operate using these principles:
- Defining steps with
createStep
, specifying input/output schemas and business logic. - Composing steps with
createWorkflow
to define the execution flow. - Running workflows to execute the entire sequence, with built-in support for suspension, resumption, and streaming results.
Creating a workflow step
Steps are the building blocks of workflows. Create a step using createStep()
with inputSchema
and outputSchema
to define the data it accepts and returns.
import { createStep } from "@mastra/core/workflows";
const step1 = createStep({
id: "step-1",
inputSchema: z.object({
message: z.string()
}),
outputSchema: z.object({
formatted: z.string()
}),
execute: async ({ inputData }) => {
const { message } = inputData;
return {
formatted: message.toUpperCase()
};
}
});
See the Step Class for a full list of configuration options.
Creating a workflow
Create a workflow using createWorkflow()
with inputSchema
and outputSchema
to define the data it accepts and returns. Add steps using .then()
and complete the workflow with .commit()
.
import { createWorkflow, createStep } from "@mastra/core/workflows";
import { z } from "zod";
const step1 = createStep({...});
export const testWorkflow = createWorkflow({
id: "test-workflow",
inputSchema: z.object({
message: z.string()
}),
outputSchema: z.object({
output: z.string()
})
})
.then(step1)
.commit();
See the Workflow Class for a full list of configuration options.
Understanding control flow
Workflows can be composed using a number of different methods. The method you choose determines how each step’s schema should be structured.
See Control Flow for more information.
Composing steps
When using .then()
, steps run sequentially. The inputSchema
of each step must match the outputSchema
of the step before it. The final step’s outputSchema
doesn’t need to match the workflow’s outputSchema
, which can be defined independently.
const step1 = createStep({
//...
inputSchema: z.object({
message: z.string()
}),
outputSchema: z.object({
formatted: z.string()
})
});
const step2 = createStep({
// ...
inputSchema: z.object({
formatted: z.string()
}),
outputSchema: z.object({
emphasized: z.string()
})
});
export const testWorkflow = createWorkflow({
// ...
inputSchema: z.object({
message: z.string()
}),
outputSchema: z.object({
output: z.string()
})
})
.then(step1)
.then(step2)
.commit();
Registering a workflow
Register your workflow in the Mastra instance to make it available throughout your application. Once registered, it can be called from agents or tools and has access to shared resources such as logging and observability features:
import { Mastra } from "@mastra/core/mastra";
import { testWorkflow } from "./workflows/test-workflow";
export const mastra = new Mastra({
// ...
workflows: { testWorkflow },
});
Referencing a workflow
You can run workflows from agents, tools, the Mastra Client, or the command line. Get a reference by calling .getWorkflow()
on your mastra
or mastraClient
instance, depending on your setup:
const testWorkflow = mastra.getWorkflow("testWorkflow");
mastra.getWorkflow()
is preferred over a direct import, since it provides access to the Mastra instance configuration (logger, telemetry, storage, registered agents, and vector stores).
See Running Workflows for more information.
Running workflows
Workflows can be run in two modes: start waits for all steps to complete before returning, and stream emits events during execution. Choose the approach that fits your use case: start when you only need the final result, and stream when you want to monitor progress or trigger actions as steps complete.
Start
Create a workflow run instance using createRunAsync()
, then call .start()
with inputData
matching the workflow’s inputSchema
. The workflow executes all steps and returns the final result.
const run = await testWorkflow.createRunAsync();
const result = await run.start({
inputData: {
message: "Hello world"
}
});
console.log(result);
Workflow output
The workflow output includes the full execution lifecycle, showing the input and output for each step. It also includes the status of each step, the overall workflow status, and the final result. This gives you clear insight into how data moved through the workflow, what each step produced, and how the workflow completed.
{
"status": "success",
"steps": {
"input": {
"message": "Hello world"
},
"step-1": {
"payload": {
"message": "Hello world"
},
"status": "success",
"output": {
"formatted": "HELLO WORLD"
},
},
"step-2": {
"payload": {
"formatted": "HELLO WORLD"
},
"status": "success",
"output": {
"emphasized": "HELLO WORLD!!!"
},
}
},
"input": {
"message": "Hello world"
},
"result": {
"emphasized": "HELLO WORLD!!!"
}
}
Using RuntimeContext
Use RuntimeContext to access request-specific values. This lets you conditionally adjust behavior based on the context of the request.
export type UserTier = {
"user-tier": "enterprise" | "pro";
};
const step1 = createStep({
// ...
execute: async ({ runtimeContext }) => {
const userTier = runtimeContext.get("user-tier") as UserTier["user-tier"];
const maxResults = userTier === "enterprise"
? 1000
: 50;
return { maxResults };
}
});
See Runtime Context for more information.
Testing with Mastra Playground
Use the Mastra Playground to easily run workflows with different inputs, visualize the execution lifecycle, see the inputs and outputs for each step, and inspect each part of the workflow in more detail.
Related
For a closer look at workflows, see our Workflow Guide, which walks through the core concepts with a practical example.
- Parallel Steps workflow example
- Conditional Branching workflow example
- Inngest workflow example
- Suspend and Resume workflow example
Workflows (Legacy)
For legacy workflow documentation, see Workflows (Legacy).