- Documentation
- Workflows
- Workflow Nodes
- Route, repeat, and parallelize steps
Route, repeat, and parallelize steps
Configure Branch, Switch, Loop, and Parallel nodes to route work by condition, iterate over arrays, and run paths concurrently.
What these nodes do
Control-flow nodes decide which steps run, how many times, and in what order. You add them from the Add node panel under the System tab, in the Control Flow category.
- Branch sends a run down a different path depending on whether each condition is true.
- Switch evaluates one value and routes to the case that matches it.
- Loop repeats a path a fixed number of times, until a condition is met, or once per item in an array.
- Parallel runs two or more paths at the same time and merges their outputs.
This page covers configuring each node and merging branches back together. To write the expressions that conditions and selectors read, see Expressions.
When to use each node
| You want to... | Use | Why |
|---|---|---|
| Take one of several paths based on true/false conditions | Branch | Each condition gets its own output path; conditions can be combined with AND/OR. |
| Route on a single value (status, type, country code) | Switch | One selector, one matching case. Cleaner than many Branch conditions. |
| Repeat work N times, until done, or per array item | Loop | Three loop modes cover counts, exit conditions, and iteration. |
| Run independent paths at once and combine results | Parallel | Concurrent branches with a merge strategy at the join. |
Configure a Branch node
A Branch node holds a list of conditions. Each condition routes to its own output path. You can also add a default path for runs that match no condition.
Add the Branch node
Open Add node, switch to the System tab, and choose Branch from the Control Flow category. Connect your upstream step into it.
Write each condition
A condition has three parts: a field (a JSONata path into upstream data, such as
$trigger.order.total), an operator, and a value. Pick the operator from the fixed list:Operator Needs a value? Equals Yes Not Equals Yes Contains Yes Not Contains Yes Greater Than Yes Less Than Yes Exists No Not Exists No ExistsandNot Existsignore the value box. Every other operator needs a non-empty value.Combine conditions with AND or OR
Set the logical operator between conditions to
ANDorOR. A Branch node requires at least 2 conditions and allows at most 8. Connect each condition's output handle to the path that should run when it matches.Add a default path (optional)
If you want a fallback for runs that match no condition, connect the node's default path handle to a downstream step.
The field is a JSONata path, but the operator and value are structured inputs you pick and type in the condition builder. You do not write a raw boolean JSONata expression for a Branch condition.
Configure a Switch node
A Switch node evaluates one selector expression, then compares its result against each case's value and routes to the first match.
Set the selector
Enter a selector, a JSONata expression that produces the value you want to route on, for example
$trigger.statusor$steps.classify.data.category. The selector cannot be empty and must be valid JSONata.Add cases
Add at least one case. Each case has a value to match and a unique path ID; you can also give it a label and description. Connect every case to the step that should run when it matches.
Choose a match mode
The match mode controls how the selector value is compared to each case value. The default is Strict.
Match mode Value Behavior Strict strictExact match with type coercion for common cases (for example, "123"=123).Loose looseAttempts type coercion before comparison. Regex regexCase values are treated as regex patterns (strings only). Contains containsChecks if the selector value contains the case value (strings/arrays). Choose no-match behavior
Decide what happens when nothing matches. The default is Default.
No-match behavior Value Result Default defaultTake the default path if configured, otherwise complete the workflow. Error errorReturn an error if no case matches and no default path exists. Skip skipSkip execution and complete the workflow gracefully. If you set a default path, connect its handle to a downstream step.
Configure a Loop node
A Loop node repeats a path. It has two output handles: continue (the loop body that runs each pass) and exit (the path taken once looping finishes). Connect both, or the publish gate warns that one is unconnected.
Pick a loop type
Choose how the loop decides when to stop:
Loop type Value What it needs Fixed Count countRuns a fixed number of times. Condition-based conditionA non-empty exit conditionexpression; repeats until the condition is met.Array Iteration arrayA non-empty arrayPath, a dot-notation path to the array, for exampledata.items.Set the maximum iterations
Every loop requires Maximum Iterations. The range is 1 to 1000. A cap above 500 raises a warning because high caps increase execution time and cost.
Reference the current item inside an array loop
Inside the body of an Array Iteration loop, two bindings are available:
$currentItem(the current element) and$currentIndex(its zero-based position). Use them in any field inside the loop body, for example$currentItem.email.Choose an execution mode (array loops only)
Array loops run sequential by default. Switch to parallel to process items concurrently. Parallel mode is only valid for Array Iteration loops; sequential loops must not carry the parallel-only fields.
When you choose parallel, set:
- Max Concurrent Iterations (
maxConcurrency), range 1 to 50, default 10. - An error policy, one of:
Error policy Behavior Continue on error Collect failures and still succeed (default). Collect errors Succeed if all items pass, fail otherwise. Fail fast Cancel remaining iterations on the first failure. - Max Concurrent Iterations (
These bindings exist only inside an Array Iteration loop's body. Referencing them outside that
body fails with SCOPE_BINDING_OUT_OF_SCOPE: move the reference inside the loop, or remove it.
See Expressions for the full scope rules.
Configure a Parallel node and merge branches
A Parallel node runs two or more branches concurrently. Each branch is one outgoing path. Their outputs come back together at the join, where a merge strategy combines them.
Define branches
A Parallel node ships with two branches ("Branch 1", "Branch 2") and requires at least 2. Each
branchIdmust be unique and non-empty. Connect each branch to the path it should run.Choose a completion mode
The completion mode sets when the block is considered done. The default is
all.Completion mode Value Behavior All allWait for every branch. Cancel on a non-skippable failure. Race raceFirst successful branch wins, remaining branches cancel. Requires at least 2 branches. Settled settledWait for all branches regardless of failures. Independent independentFire and forget. Branches run with no barrier. Choose a merge strategy
The merge strategy decides how branch outputs combine at the join. The default is
array. This is only meaningful when the completion mode is notindependent.Merge strategy Value Result Array arrayEach successful branch's output, keyed by branchId.First firstThe output of the first successful branch in definition order. Merge mergeSuccessful branch outputs shallow-merged into one object. Set per-branch and group limits (optional)
Tune these when you need them; all default to "off":
- skipFailure (per branch, default
false): when true, that branch failing does not fail the block. - branchTimeoutMs (per branch, default
0= no timeout) and groupTimeoutMs (whole block, default0= no timeout). Both must be non-negative. - maxConcurrency (default
0= unlimited). A value larger than the branch count raises a warning. Must be non-negative.
- skipFailure (per branch, default
After the join, downstream steps receive a structured output:
resultsis an array of branch results, ordered by branch definition (not completion order).mergedDataholds the successful branches' data, keyed bybranchId.summaryreports counts (succeeded,failed,cancelled,timedOut,total) and areleaseReasonofall_completed,failure_threshold,race_winner, ortimeout.
Read these with $steps, for example $steps.parallel1.data.summary.succeeded or $steps.parallel1.data.mergedData.branch-0.
Verify your configuration
Each control-flow node has a test button in its configuration panel ("Test branch", "Test switch", "Test loop"). Testing runs the node for real against pinned upstream output, so route decisions reflect actual data.
The test button only fires once the node is valid. For example, an unconfigured Switch shows the tooltip "Configure a selector and at least one valid case before testing." Configure the node until the button enables, then run the test and confirm the run took the path you expected. See Test a node and publish for the full test-then-publish flow.
Troubleshooting
These messages come from the publish gate. A version cannot enter the live cohort until every one clears.
| Message | Node | Fix |
|---|---|---|
| Branch node must have at least 2 conditions | Branch | Add conditions until you have at least 2 (max 8). |
| Branch node has too many conditions (maximum 8) | Branch | Remove conditions to get back to 8 or fewer. |
| Switch node must have a selector expression | Switch | Enter a non-empty selector. |
| Invalid selector expression | Switch | Fix the JSONata so the selector compiles. |
| Switch node must have at least one case | Switch | Add at least one case. |
Duplicate pathId "<id>" found in cases | Switch | Give each case a unique path ID. |
| maxIterations is required | Loop | Set Maximum Iterations (1 to 1000). |
| maxIterations cannot exceed 1000 | Loop | Lower the cap to 1000 or less. |
| Array path is required for array-type loops | Loop | Set arrayPath (for example data.items). |
| Condition expression is required for condition-type loops | Loop | Enter the exit condition expression. |
| Loop node has no incoming edges and will never be executed | Loop | Connect an upstream step into the Loop. |
| Parallel node must have at least 2 branches | Parallel | Keep at least 2 branches. |
Duplicate branchId "<id>" found | Parallel | Make each branchId unique. |
| Each branch must have a non-empty branchId | Parallel | Give every branch an ID. |
A common case worth calling out: when you add a Branch or Switch case but forget to connect its handle, the publish gate fails with "Branch node condition <n> (handle: condition-<i>) has no connected edge" or "Switch node case <label> (pathId: <id>) has no connected edge". Connect every condition and case to a downstream step, including the default path if you configured one. The same applies to a Loop: connect both the continue and exit handles. For the complete publish-gate reference, see Fix publish errors.
Related
- Expressions for the JSONata aliases conditions and selectors read.
- Test a node and publish for testing nodes and clearing the publish gate.
- Fix publish errors for the full list of validation messages.