Loop steps
A loop step runs the same saved workflow many times as part of your current workflow — once per item in a list, or a fixed number of times. You build the child once, then the loop starts every child run together and waits until they all finish before the parent continues.
Use a loop when you need the same mini-process applied to many values without copying a sub-workflow step for each one.
When to use a loop
| Approach | Best for |
|---|---|
| Sub-workflow | One child, one run |
| Loop | A list whose length changes, or many items (up to 100 per step) |
| Several sub-workflow steps | A small, fixed number of distinct calls (e.g. exactly two workspaces) |
Good reasons to use a loop:
- Process every item in a workflow input list — workspaces, document IDs, email addresses.
- Repeat an action N times when the count comes from data or configuration.
- Keep the parent readable — one loop step instead of ten identical sub-workflow steps.
Two loop modes
| Mode | Editor field | Use when |
|---|---|---|
| Foreach | Items array — a list or expression such as {{ workflow_inputs.workspaces }} | Run the child once per array element |
| Times | Iteration count — a number or expression | Run the child a fixed number of times |
You set Loop mode in the step configuration. Foreach requires Items array; Times requires Iteration count — not both.
Step 1 — Build the child workflow
Create the reusable child workflow first, exactly as for a sub-workflow:
- Go to Workflows → Create workflow and save the child with a clear name.
- Under Workflow inputs, add the fields the loop will supply on each iteration (for example
workspace_id). - Add steps that use those inputs.
- Under Outputs, map the results callers need (for example
ws_infofrom a tool step).
Run the child on its own with sample inputs before wiring the parent. If the child works alone, each loop iteration will have reliable data.
Step 2 — Add a loop step in the parent
- Open the parent workflow in the editor.
- Click Add Step, or choose From Template and pick Loop - Foreach over array or Loop - Repeat N times.
- Set Step kind to Loop.
- Under Target workflow, choose the child workflow (the picker excludes the current workflow).
- Choose Loop mode — Foreach or Times.
- Set Items array (foreach) or Iteration count (times).
Passing values into each child run
Each iteration is a separate child execution. You control what the child receives in two places.
Input mapping (per iteration)
Under Input mapping, add one row per child workflow input you want to set on each iteration. The child defines which names exist — you are not limited to a fixed set. Map as many or as few as the child needs.
Example (foreach over workspace objects; your child may have different input names):
| Child input | Value source | Expression |
|---|---|---|
workspace_id | From expression | {{ context.loop_item.id }} |
mode | Provided | info (same every iteration) |
After you pick a target workflow, use Prepare input mappings to pre-fill rows from the child’s workflow inputs, then adjust expressions.
Loop iteration expressions
Input mapping values use the same formula syntax as other workflow steps — workflow_inputs, earlier steps, and so on. See Workflow authoring for the full reference.
On a loop step, these additional expressions are also available in mapping values (evaluated in the parent while each child run is started). They are not available inside the child unless you map them into a workflow input:
| Expression | Meaning |
|---|---|
{{ context.loop_item }} | Current array element (foreach mode) |
{{ context.loop_item.id }} | Field access on an object element |
{{ context.loop_index }} | 0-based iteration index (0, 1, 2, …) |
{{ context.loop_total }} | Total number of iterations (foreach mode) |
You can combine them with other sources — for example {{ workflow_inputs.batch_label }} on every iteration, or {{ steps.fetch_list.outputs.ids[context.loop_index] }} when an earlier step produced the data.
For Times mode, context.loop_index and context.loop_total are the usual choices when the child needs to know which pass it is.
Step Inputs tab (shared every iteration)
Values that are identical for every run belong on the loop step’s Inputs tab — for example a shared folder name or API mode. They are passed to every child execution unchanged.
Index input name (optional shortcut)
Instead of mapping {{ context.loop_index }} manually, you can set Index input name to a child workflow input (for example iteration). The platform writes the 0-based index into that input on each run.
Getting outputs back
When every child run has finished, the loop step exposes aggregated outputs:
| Output | Meaning |
|---|---|
items_count | Number of iterations executed |
results | Array of per-iteration child workflow output values (one object per run) |
subworkflow_execution_ids | Child execution IDs, in iteration order |
subworkflow_executions | Per-iteration diagnostics (index, state, execution id) |
subworkflow_workflow_id | ID of the target child workflow |
Each entry in results uses the names from the child’s workflow outputs. If an iteration’s child run failed or was cancelled, that entry includes subworkflow_error and the output values are null.
Reference results in later steps with formulas — for example:
{{ steps.lookup_all.outputs.results[0].ws_info }} For formula syntax, see Workflow authoring.
At the bottom of the parent editor, you can also map workflow outputs from the loop step — for example expose the full results array or a single indexed item.
Worked example: foreach over workspaces
Parent input: workspaces — a list of workspace objects. One loop step calls the same child for every item. Top-level output all_ws_info collects the results array.
Child workflow (same as the sub-workflow example):
name: sub-workflow-child
description: Look up workspace details for use by other workflows
version: 1.0.0
scope: account
enabled: true
trigger:
kind: manual
contexts:
- chat
workflow_inputs:
- name: workspace_id
type: string
required: false
steps:
- name: get_workspace_info
kind: tool
config:
tool_name: workspace_tool
action: info
workspace_id: "{{ workflow_inputs.workspace_id }}"
on_error: fail
description: Show workspace details
error_handling:
mode: fail_fast
workflow_outputs:
- name: ws_info
step_id: get_workspace_info
field: data Parent workflow:
name: parent-workflow
version: 1.0.0
scope: account
enabled: true
trigger:
kind: manual
contexts:
- chat
workflow_inputs:
- name: workspaces
type: array
required: false
default: []
steps:
- name: lookup_all
kind: loop
config:
mode: foreach
items: "{{ workflow_inputs.workspaces }}"
workflow_id: "<your-child-workflow-id>"
workflow_name: sub-workflow-child
input_mappings:
- input: workspace_id
value_source: from_expression
value: "{{ context.loop_item.id }}"
on_error: fail
error_handling:
mode: fail_fast
workflow_outputs:
- name: all_ws_info
step_id: lookup_all
field: results Replace <your-child-workflow-id> with the ID from the target picker (you do not need to type this when using the visual editor).
This replaces two separate sub-workflow steps (one per workspace) with a single loop that scales to any list length.
Running and checking results
- Trigger the parent workflow as usual.
- While child runs are in progress, the loop step shows Awaiting loop.
- When every child has finished, the step moves to Completed or Failed.
- On the execution detail page, expand the loop step to inspect
results,items_count, andsubworkflow_execution_ids.
When some iterations fail
By default (Error policy: Fail), the loop step fails if any child run fails or is cancelled — even when other iterations succeeded. Check results for subworkflow_error on the failed entries.
- Skip — the loop step is marked skipped but outputs (including partial
results) are still recorded. - Default value — the loop step completes successfully; inspect
resultsto see which iterations failed.
Limits and tips
- Maximum 100 iterations per loop step.
- An empty items array in foreach mode runs zero children; the step completes with
items_count: 0. - Name child inputs and outputs clearly — they are the contract between the loop and the child.
- Test the child first with realistic inputs before connecting the parent.
- Map loop context explicitly — the child never sees
context.loop_itemunless you pass it through input mapping or the step Inputs tab. - Save and validate — if the child workflow is missing or disabled, the editor will warn you.
Related guides
- Sub-workflows — call a child workflow once and map inputs/outputs
- Workflow authoring — formulas, chaining, and step kinds
- Workflows overview — triggers, execution history, and error handling
- Human approval — pause for review after a loop returns, before anything irreversible