Skip to main content

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:

Diagram showing workflow with branching paths

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 source on GitHub

`

Workflows (Legacy)​

The following links provide example documentation for legacy workflows: