Documentation

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

ApproachBest for
Sub-workflowOne child, one run
LoopA list whose length changes, or many items (up to 100 per step)
Several sub-workflow stepsA 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

ModeEditor fieldUse when
ForeachItems array — a list or expression such as {{ workflow_inputs.workspaces }}Run the child once per array element
TimesIteration count — a number or expressionRun 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:

  1. Go to Workflows → Create workflow and save the child with a clear name.
  2. Under Workflow inputs, add the fields the loop will supply on each iteration (for example workspace_id).
  3. Add steps that use those inputs.
  4. Under Outputs, map the results callers need (for example ws_info from 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

  1. Open the parent workflow in the editor.
  2. Click Add Step, or choose From Template and pick Loop - Foreach over array or Loop - Repeat N times.
  3. Set Step kind to Loop.
  4. Under Target workflow, choose the child workflow (the picker excludes the current workflow).
  5. Choose Loop modeForeach or Times.
  6. 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 inputValue sourceExpression
workspace_idFrom expression{{ context.loop_item.id }}
modeProvidedinfo (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:

ExpressionMeaning
{{ 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:

OutputMeaning
items_countNumber of iterations executed
resultsArray of per-iteration child workflow output values (one object per run)
subworkflow_execution_idsChild execution IDs, in iteration order
subworkflow_executionsPer-iteration diagnostics (index, state, execution id)
subworkflow_workflow_idID 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

  1. Trigger the parent workflow as usual.
  2. While child runs are in progress, the loop step shows Awaiting loop.
  3. When every child has finished, the step moves to Completed or Failed.
  4. On the execution detail page, expand the loop step to inspect results, items_count, and subworkflow_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 results to 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_item unless 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