> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ingestly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Iterating over arrays

> Run a group of nodes once per item with the Loop container.

The **Loop** node is the standard answer when an extracted document yields a variable-length list (line items, attachments, contacts) and you need to act on each entry. It is a container: drop nodes inside it and they run once per item.

## Build it

1. Add a **Loop** node and set its **Source** to a template expression that resolves to an array, for example `{{extract.payload.lineItems}}`.
2. Connect the node that produces the array **into the Loop**.
3. **Drag the nodes that should run per item inside the Loop.** These are the loop *body*; they run once for every item, in array order.
4. Inside the body, reference the current item with `{{loop.payload.item}}` and its index with `{{loop.payload.index}}` (where `loop` is the loop node's name).
5. If something must run after the loop, connect those downstream nodes **from the Loop**, not from a node inside it. A downstream connection is optional: the Loop can end a branch on its own.

The whole loop runs as a **single sub-run**. Open it from the run detail and use the item pager to step through each item's output.

<Note>
  **Atomic failure.** If any item fails, the loop stops immediately and the step fails, so the remaining items do not run. A loop's Store writes are held until every item succeeds and are committed only then, so a failed loop persists nothing to the Store.
</Note>

## What can go inside

A loop body may only contain Transform, Validation, Store, and Variable nodes. Extract, Review, Filter, Split, Classify, HTTP, the output nodes (including Callback Output), Reconcile, Merge, and nested Loops belong before or after the loop, not inside it. A single loop may iterate over at most **500 items**. See the [Loop node reference](/nodes/loop) for the full rules.

## Referencing items

Inside the body, per item:

* `{{loop.payload.item}}` for the current item
* `{{loop.payload.index}}` for its 0-based position
* `{{loop.metadata.itemCount}}` for the total count

After the loop, from downstream nodes:

* `{{loop.payload.results}}` for the full resolved array
* `{{loop.metadata.itemCount}}` for the count

<Tip>Per-item bindings accept the full filter chain, so you can transform an item inline, for example `{{loop.payload.item.amount | round: 2}}` or `{{loop.payload.item.sku | upper}}`. See [expressions and filters](/guides/expressions).</Tip>

## Recipes

**Send extracted items to a callback.**

Output and HTTP nodes can't run inside a loop, so there is no per-item callback from the loop body. Put a **Callback Output** *after* the loop (or anywhere downstream) and send the full array in one request:

```json theme={null}
{
  "lines": "{{loop.payload.results}}"
}
```

For per-item HTTP against an OData endpoint, see the **\$batch** path on the [Business Central guide](/guides/business-central).

**Count items and branch on a threshold.**

Add a **Condition** edge *from the Loop* with the rule `{{loop.metadata.itemCount}} >= 10`, and an **Otherwise** edge to the alternative path.

## Related

* [Loop node reference](/nodes/loop) for configuration, limits, and errors.
* [Expressions and filters](/guides/expressions) for filter syntax (`length`, `first`, `sum`, and so on).
* [Conditional routing](/guides/conditional-routing) for branching on item counts and other rules.
