Branching Paths
When processing data, you often need to take different actions based on intermediate results. This example shows how to create a legacy workflow that splits into separate paths, where each path executes different steps based on the output of a previous step.
Control Flow Diagram
This example shows how to create a legacy workflow that splits into separate paths, where each path executes different steps based on the output of a previous step.
Here’s the control flow diagram:

Creating the Steps
Let’s start by creating the steps and initializing the workflow.
import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy";
import { z } from "zod"
const stepOne = new LegacyStep({
id: "stepOne",
execute: async ({ context }) => ({
doubledValue: context.triggerData.inputValue * 2
})
});
const stepTwo = new LegacyStep({
id: "stepTwo",
execute: async ({ context }) => {
const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne");
if (!stepOneResult) {
return { isDivisibleByFive: false }
}
return { isDivisibleByFive: stepOneResult.doubledValue % 5 === 0 }
}
});
const stepThree = new LegacyStep({
id: "stepThree",
execute: async ({ context }) =>{
const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne");
if (!stepOneResult) {
return { incrementedValue: 0 }
}
return { incrementedValue: stepOneResult.doubledValue + 1 }
}
});
const stepFour = new LegacyStep({
id: "stepFour",
execute: async ({ context }) => {
const stepThreeResult = context.getStepResult<{ incrementedValue: number }>("stepThree");
if (!stepThreeResult) {
return { isDivisibleByThree: false }
}
return { isDivisibleByThree: stepThreeResult.incrementedValue % 3 === 0 }
}
});
// New step that depends on both branches
const finalStep = new LegacyStep({
id: "finalStep",
execute: async ({ context }) => {
// Get results from both branches using getStepResult
const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean }>("stepTwo");
const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean }>("stepFour");
const isDivisibleByFive = stepTwoResult?.isDivisibleByFive || false;
const isDivisibleByThree = stepFourResult?.isDivisibleByThree || false;
return {
summary: `The number ${context.triggerData.inputValue} when doubled ${isDivisibleByFive ? 'is' : 'is not'} divisible by 5, and when doubled and incremented ${isDivisibleByThree ? 'is' : 'is not'} divisible by 3.`,
isDivisibleByFive,
isDivisibleByThree
}
}
});
// Build the workflow
const myWorkflow = new LegacyWorkflow({
name: "my-workflow",
triggerSchema: z.object({
inputValue: z.number(),
}),
});
Branching Paths and Chaining Steps
Now let’s configure the legacy workflow with branching paths and merge them using the compound .after([])
syntax.
// Create two parallel branches
myWorkflow
// First branch
.step(stepOne)
.then(stepTwo)
// Second branch
.after(stepOne)
.step(stepThree)
.then(stepFour)
// Merge both branches using compound after syntax
.after([stepTwo, stepFour])
.step(finalStep)
.commit();
const { start } = myWorkflow.createRun();
const result = await start({ triggerData: { inputValue: 3 } });
console.log(result.steps.finalStep.output.summary);
// Output: "The number 3 when doubled is not divisible by 5, and when doubled and incremented is divisible by 3."
Advanced Branching and Merging
You can create more complex workflows with multiple branches and merge points:
const complexWorkflow = new LegacyWorkflow({
name: "complex-workflow",
triggerSchema: z.object({
inputValue: z.number(),
}),
});
// Create multiple branches with different merge points
complexWorkflow
// Main step
.step(stepOne)
// First branch
.then(stepTwo)
// Second branch
.after(stepOne)
.step(stepThree)
.then(stepFour)
// Third branch (another path from stepOne)
.after(stepOne)
.step(
new LegacyStep({
id: "alternativePath",
execute: async ({ context }) => {
const stepOneResult = context.getStepResult<{ doubledValue: number }>(
"stepOne",
);
return {
result: (stepOneResult?.doubledValue || 0) * 3,
};
},
}),
)
// Merge first and second branches
.after([stepTwo, stepFour])
.step(
new LegacyStep({
id: "partialMerge",
execute: async ({ context }) => {
const stepTwoResult = context.getStepResult<{
isDivisibleByFive: boolean;
}>("stepTwo");
const stepFourResult = context.getStepResult<{
isDivisibleByThree: boolean;
}>("stepFour");
return {
intermediateResult: "Processed first two branches",
branchResults: {
branch1: stepTwoResult?.isDivisibleByFive,
branch2: stepFourResult?.isDivisibleByThree,
},
};
},
}),
)
// Final merge of all branches
.after(["partialMerge", "alternativePath"])
.step(
new LegacyStep({
id: "finalMerge",
execute: async ({ context }) => {
const partialMergeResult = context.getStepResult<{
intermediateResult: string;
branchResults: { branch1: boolean; branch2: boolean };
}>("partialMerge");
const alternativePathResult = context.getStepResult<{ result: number }>(
"alternativePath",
);
return {
finalResult: "All branches processed",
combinedData: {
fromPartialMerge: partialMergeResult?.branchResults,
fromAlternativePath: alternativePathResult?.result,
},
};
},
}),
)
.commit();
View Example on GitHub
`