Workflow Runtime Variables
Mastra provides a powerful dependency injection system that enables you to configure your workflows and steps with runtime variables. This feature is essential for creating flexible and reusable workflows that can adapt their behavior based on runtime configuration.
Overview
The dependency injection system allows you to:
- Pass runtime configuration variables to workflows through a type-safe runtimeContext
- Access these variables within step execution contexts
- Modify workflow behavior without changing the underlying code
- Share configuration across multiple steps within the same workflow
Basic Usage
const myWorkflow = mastra.getWorkflow("myWorkflow");
const { runId, start, resume } = myWorkflow.createRun();
// Define your runtimeContext's type structure
type WorkflowRuntimeContext = {
multiplier: number;
};
const runtimeContext = new RuntimeContext<WorkflowRuntimeContext>();
runtimeContext.set("multiplier", 5);
// Start the workflow execution with runtimeContext
await start({
triggerData: { inputValue: 45 },
runtimeContext,
});
Using with REST API
Here’s how to dynamically set a multiplier value from an HTTP header:
src/index.ts
import { Mastra } from "@mastra/core";
import { RuntimeContext } from "@mastra/core/di";
import { workflow as myWorkflow } from "./workflows";
// Define runtimeContext type with clear, descriptive types
type WorkflowRuntimeContext = {
multiplier: number;
};
export const mastra = new Mastra({
workflows: {
myWorkflow,
},
server: {
middleware: [
async (c, next) => {
const multiplier = c.req.header("x-multiplier");
const runtimeContext = c.get<WorkflowRuntimeContext>("runtimeContext");
// Parse and validate the multiplier value
const multiplierValue = parseInt(multiplier || "1", 10);
if (isNaN(multiplierValue)) {
throw new Error("Invalid multiplier value");
}
runtimeContext.set("multiplier", multiplierValue);
await next(); // Don't forget to call next()
},
],
},
});
Creating Steps with Variables
Steps can access runtimeContext variables and must conform to the workflow’s runtimeContext type:
import { Step } from "@mastra/core/workflow";
import { z } from "zod";
// Define step input/output types
interface StepInput {
inputValue: number;
}
interface StepOutput {
incrementedValue: number;
}
const stepOne = new Step({
id: "stepOne",
description: "Multiply the input value by the configured multiplier",
execute: async ({ context, runtimeContext }) => {
try {
// Type-safe access to runtimeContext variables
const multiplier = runtimeContext.get("multiplier");
if (multiplier === undefined) {
throw new Error("Multiplier not configured in runtimeContext");
}
// Get and validate input
const inputValue =
context.getStepResult<StepInput>("trigger")?.inputValue;
if (inputValue === undefined) {
throw new Error("Input value not provided");
}
const result: StepOutput = {
incrementedValue: inputValue * multiplier,
};
return result;
} catch (error) {
console.error(`Error in stepOne: ${error.message}`);
throw error;
}
},
});
Error Handling
When working with runtime variables in workflows, it’s important to handle potential errors:
- Missing Variables: Always check if required variables exist in the runtimeContext
- Type Mismatches: Use TypeScript’s type system to catch type errors at compile time
- Invalid Values: Validate variable values before using them in your steps
// Example of defensive programming with runtimeContext variables
const multiplier = runtimeContext.get("multiplier");
if (multiplier === undefined) {
throw new Error("Multiplier not configured in runtimeContext");
}
// Type and value validation
if (typeof multiplier !== "number" || multiplier <= 0) {
throw new Error(`Invalid multiplier value: ${multiplier}`);
}
Best Practices
- Type Safety: Always define proper types for your runtimeContext and step inputs/outputs
- Validation: Validate all inputs and runtimeContext variables before using them
- Error Handling: Implement proper error handling in your steps
- Documentation: Document the expected runtimeContext variables for each workflow
- Default Values: Provide sensible defaults when possible