FormWork documentation
For Each Loops
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
- Add For Each Loop.
- Use the reference picker to select the list in Items.
- Connect Loop Body to the first step that should run for each item.
- Connect the loop-body steps in their execution order.
- Connect After Loop to the step that should run once when iteration finishes.
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:
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:
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:
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:
iteration:<for-each-step-id>.steps.<body-step-id>.outputs.<output-id>
For example, if calculate_line defines a line_total calculation:
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
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.