# For Each Loops

Canonical: https://useformwork.com/docs/workflows/for-each

Run workflow steps once for every item in a list.

The **For Each Loop** step evaluates a list reference and runs its loop body once for every item. After the last item, execution continues through **After Loop**.

## Build a Loop

1. Add **For Each Loop**.
2. Use the reference picker to select the list in **Items**.
3. Connect **Loop Body** to the first step that should run for each item.
4. Connect the loop-body steps in their execution order.
5. Connect **After Loop** to the step that should run once when iteration finishes.

```text
For Each
├─ Loop Body  → Step A → Step B
└─ After Loop → Next step
```

An empty list skips the loop body and continues through **After Loop**.

## List Sources

Examples include:

```text
entry:current.answers.selected_categories
entry:current.answers.line_items
data_table:<table-id>.rows[cells.active=true]
workflow:current.steps.build_items.outputs.items
```

A repeater's top-level answer is a list of instance keys. Its child values remain in flat answer paths, so use the current iteration key to address a child:

```text
entry:current.answers.line_items[{iteration:for_each_line.key}].quantity
```

## Read the Current Item

References inside the body are rooted at the For Each step ID:

```text
iteration:<for-each-step-id>.index
iteration:<for-each-step-id>.key
iteration:<for-each-step-id>.item
iteration:<for-each-step-id>.item.<field>
```

| Reference | Meaning |
|-----------|---------|
| `index` | Zero-based position in the list |
| `key` | Current item ID or repeater instance key |
| `item` | Current scalar, object, or row |

For a data table row object, the reference picker can navigate from the current item to its available row and cell values. For a simple array, `item` is the scalar value itself.

## Read a Body Step's Output

Loop-body step outputs are scoped to the current iteration:

```text
iteration:<for-each-step-id>.steps.<body-step-id>.outputs.<output-id>
```

For example, if `calculate_line` defines a `line_total` calculation:

```text
iteration:for_each_line.steps.calculate_line.outputs.line_total
```

Use that reference only in later steps within the same loop iteration.

## After the Loop

The For Each step records iteration count in the workflow run log, but it does not publish an aggregate `iter_outputs` value for downstream steps. Loop-body outputs are not a collected array after the loop.

If a result is needed after the loop, write each durable result to an entry or row during the body, then read the updated data after **After Loop**. When possible, calculate an aggregate directly from the original collection instead of collecting per-iteration workflow outputs.

## Nested Loops

The workflow editor does not allow a For Each step inside another For Each loop. Flatten the source list first or split multi-level processing into separate workflows.

## Failure Behavior

If a step in the loop body fails, the workflow run fails; FormWork does not silently continue with the next item. An Extension Action can use its `error` path when the HTTP request completes with a non-2xx status, but network, configuration, and reference errors still fail the run.

## Example: Update Repeater Line Totals

```text
For Each: entry:current.answers.line_items
└─ Loop Body
   ├─ Calculation step ID: calculate_line
   │  line_total = quantity × unit price
   └─ Update Entry/Row
      target: entry:current.answers.line_items[{iteration:for_each_line.key}].line_total
      value: iteration:for_each_line.steps.calculate_line.outputs.line_total
```

Use the reference and mapping pickers to build the actual formula, target, and value. The displayed labels can differ, but the reference strings use the stable step and field IDs.

## Good Practices

- Test with an empty list, one item, and several items.
- Keep the body small because its steps run once per item.
- Avoid one external API request per item when the service offers a batch action.
- Write results that must survive the current iteration back to an entry or row.
- Inspect the run log to see the recorded iterations and the failing body step.