Flow Control & Conditions
Basic Conditional Flow
Use conditions to control which steps execute next:
{
"id": "check-status",
"action": "template::api_call",
"parameters": {
"url": "https://api.example.com/status"
},
"condition": {
"if": "{{check-status.output.status}} == 'success'",
"then": "process-data",
"else": "handle-error"
}
}
Complex Conditions
Support for complex logical expressions:
{
"condition": {
"if": "{{previous-step.output.user.role}} == 'admin' && {{another-step.output.boolean_variable}} == true",
"then": "priority-processing",
"else": "standard-processing"
}
}
Multiple Next Steps
Execute multiple steps in parallel:
{
"id": "fan-out-step",
"action": "builtin::log",
"parameters": {
"message": "Starting parallel processing"
},
"next": ["process-images", "process-text", "update-database"]
}
Work also with conditions.
Convergence Points
Synchronize multiple parallel branches at a convergence point using the waitForAll field:
{
"id": "step-convergence",
"name": "Wait for All Branches",
"action": "builtin::log",
"waitForAll": true,
"parameters": {
"message": "All branches completed: {{branch-a.output.result}} and {{branch-b.output.result}}"
}
}
How Convergence Works:
- Steps with
"waitForAll": truewait for all their dependencies to complete before executing - Dependencies are automatically detected from template variables (e.g.,
{{branch-a.output}}) - The step only executes once, even if multiple branches redirect to it
- Prevents race conditions and ensures all required data is available
Example Fan-Out/Fan-In Workflow:
{
"steps": [
{
"id": "start",
"action": "builtin::log",
"parameters": {"message": "Starting parallel workflow"},
"next": ["branch-a", "branch-b", "branch-c"]
},
{
"id": "step-branch-a",
"action": "builtin::transform",
"parameters": {"rules": {"result": "Data from A"}},
"next": ["convergence-point"]
},
{
"id": "step-branch-b",
"action": "builtin::transform",
"parameters": {"rules": {"result": "Data from B"}},
"next": ["convergence-point"]
},
{
"id": "step-branch-c",
"action": "builtin::delay",
"parameters": {"seconds": 3},
"next": ["convergence-point"]
},
{
"id": "step-convergence-point",
"waitForAll": true,
"action": "builtin::log",
"parameters": {
"message": "All done: A={{branch-a.output.transformed.result}}, B={{branch-b.output.transformed.result}}"
}
}
]
}
Without Convergence:
convergence-pointwould execute 3 times (once per branch)- Template variables might be
nullif referenced branches haven't completed yet
With Convergence:
convergence-pointwaits until all branches (branch-a,branch-b,branch-c) complete- Executes only once with all data available
- Handles timing differences automatically (e.g.,
branch-cdelay)
Workflow Control Actions
Special keywords can control workflow execution flow in both condition statements and onError handlers:
Control Keywords
"stop-workflow"- Immediately stops the entire workflow"continue-workflow"- Continues execution (mainly used in error handling)"retry-step"- Retries the current step (error handling only)"retry-workflow"- Restarts the entire workflow from the beginning
For more information, see the Error Handling documentation.
Loop Iteration System
The logic::loop action executes subsequent workflow steps multiple times, once per item (or batch of items):
{
"id": "prepare-items",
"action": "builtin::transform",
"parameters": {
"rules": {
"files": ["file1.txt", "file2.txt", "file3.txt"]
}
},
"next": ["loop-files"]
},
{
"id": "loop-files",
"action": "logic::loop",
"parameters": {
"items": "{{prepare-items.output.transformed.files}}",
"batchSize": 1
},
"next": ["process-file", "validate-file"]
}
How it works:
- Takes an array of
items(required) - Optional
batchSizeparameter (default: 1) to process items in batches - Queues all steps in the
nextfield for all iterations upfront - Each iteration sets
{{loop_item}}and{{loop_index}}context variables before executing - Multiple branches execute in parallel - if
nextcontains multiple steps, they run as async branches - Within each branch, iterations execute sequentially - iteration N+1 waits for iteration N to complete
- This ensures reliable execution and API rate limit management within each processing branch
- Returns
{"count": N, "batchSize": X, "iterations": Y}with loop metadata
Parameters:
items- Array of items to iterate over (required, must be a list)batchSize- Number of items per iteration (optional, default: 1)
Available context variables during each iteration:
{{loop_item}}- Current item being processed (single item if batchSize=1, array if batchSize>1){{loop_index}}- Current iteration index (0-based)
Important: Loop variables ({{loop_item}} and {{loop_index}}) are cleared once all iterations are processed and synchronized with waitForAll.
Example with batch processing:
{
"id": "loop-batch",
"action": "logic::loop",
"parameters": {
"items": ["item1", "item2", "item3", "item4", "item5"],
"batchSize": 2
},
"next": ["process-batch"]
},
{
"id": "process-batch",
"action": "builtin::log",
"parameters": {
"message": "Processing batch [{{loop_index}}]: {{loop_item}}"
}
}
This will execute process-batch 3 times:
- Iteration 0:
loop_item = ["item1", "item2"],loop_index = 0 - Iteration 1:
loop_item = ["item3", "item4"],loop_index = 1 - Iteration 2:
loop_item = ["item5"],loop_index = 2
Loop Convergence with waitForAll:
Steps with waitForAll: true after a loop will wait for ALL iterations across ALL branches to complete:
{
"id": "loop-process",
"action": "logic::loop",
"parameters": {
"items": ["a", "b", "c"]
},
"next": ["process-item", "validate-item"]
},
{
"id": "process-item",
"action": "builtin::log",
"parameters": {
"message": "Processing: {{loop_item}}"
},
"next": ["convergence"]
},
{
"id": "validate-item",
"action": "builtin::log",
"parameters": {
"message": "Validating: {{loop_item}}"
},
"next": ["convergence"]
},
{
"id": "convergence",
"waitForAll": true,
"action": "builtin::log",
"parameters": {
"message": "All 6 executions complete (3 items x 2 branches)"
}
}
How async branches work with loops:
- The two branches (
process-itemandvalidate-item) execute in parallel - Within
process-itembranch: iteration 0 → iteration 1 → iteration 2 (sequential) - Within
validate-itembranch: iteration 0 → iteration 1 → iteration 2 (sequential) - Both branches run independently and may complete at different times
- The
convergencestep waits until all 6 executions finish (3 iterations × 2 branches)
Failed Iterations and Error Handling:
When an iteration fails after exhausting its retry limit (see onError.maxRetries):
- The failed iteration does not queue next steps for that iteration
- Other iterations in the same branch continue executing normally
waitForAllsteps will proceed once all iterations complete (whether successful or failed)- This ensures the workflow continues even if some items fail processing
Example with 5 files where file 2 fails after 3 retries:
{
"id": "loop-files",
"action": "logic::loop",
"parameters": {
"items": ["file1", "file2", "file3", "file4", "file5"]
},
"next": ["download-file"]
},
{
"id": "download-file",
"action": "addon::download",
"onError": {
"action": "retry-step",
"maxRetries": 3
},
"next": ["process-file"]
}
Result:
- File 2 iteration stops after exhausting retries (does not queue
process-file) - Files 1, 3, 4, 5 continue and queue
process-file process-fileexecutes 4 times (only for successful downloads)- If there's a
waitForAllconvergence step afterprocess-file, it waits for those 4 executions
Loop Item Validation:
- If
itemsisnullorNone, the loop defaults to an empty list and logs a warning - If
itemsis not a list, the loop returns an error and stops execution - Next steps will not be queued if items is empty