Skip to 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 Example on GitHub

`