> ## 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.

# Loop node

> Run a group of nodes once per item in an array resolved from upstream.

<Note>This node is in **preview**. Its behavior may change in future releases.</Note>

The **Loop** node is a container. Drop nodes inside it and they run once for every item in an array you resolve from upstream; nodes outside the loop run once, as usual. Reach for it when an extracted document yields a variable-length list (line items, attachments, contacts) and you need to act on each entry.

## How it works

* **Drag nodes inside the Loop** to make them its *body*. The body runs once per item, in array order.
* Inside the body, reference the current item with `{{loop.payload.item}}` and its position with `{{loop.payload.index}}` (0-based), where `loop` is the loop node's name.
* The whole loop runs as a **single sub-run**, not one run per item. Open it from the run detail and use the item pager to step through each item's output.
* Items are processed **one at a time, in array order**.

<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 (or one interrupted by a worker restart) persists nothing to the Store. A Store node reading inside the same loop sees only already-committed entries, never the loop's own pending writes.
</Note>

## What can go inside

A loop body may only contain these node types:

* Transform
* Validation
* Store
* Variable

Extract, Review, Filter, Split, Classify, HTTP, the output nodes (Email, Forward, Download, Callback Output), Reconcile, Merge, and **nested Loops** are not allowed inside a loop. Place those before or after the loop instead. HTTP and Callback Output are excluded because a stopped or retried loop could re-fire a per-item external request that has no idempotency key. Do that work after the loop, or use a batch endpoint.

## Connecting nodes

* Connect the node that produces the array **to the Loop** (an edge into the loop node).
* Connect downstream nodes **from the Loop**, not from a node inside it. Edges may not cross the loop boundary.
* The Loop's own outgoing connection is optional. Because the body does the per-item work, a Loop may end a branch (like a Store node in Set mode). Its source handle stays, so you can still wire it onward to downstream nodes when you need results after the loop.
* Wire body nodes to each other inside the loop as normal. For a given item, each body node can read the previous body node's output for that same item.

## 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 number of items

After the loop, from downstream nodes:

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

(Replace `loop` with your loop node's actual name.)

## Configuration

| Field                    | Description                                                                                                                     |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| **Source**               | A template expression that resolves to an array, for example `{{extract.payload.lineItems}}` or `{{aggregator.payload.items}}`. |
| **Sequential execution** | Currently has no effect: a loop always processes its items one at a time, in array order.                                       |

## Limits

A single loop may iterate over at most **500 items**. A larger source array fails the step with a clear error rather than attempting it. Filter or page the array upstream so the loop runs over fewer items.

## Errors

* **Source expression is required**: the Source field is empty.
* **Source expression resolved to a non-array value**: the expression resolved to something other than a JSON array (an object, a string, and so on). Check the upstream output and the path you reference.
* **Loop has no body nodes**: the loop is empty. Drag at least one node inside it.
* **A node cannot be inside a Loop**: a body node is of a type the loop does not allow (see [What can go inside](#what-can-go-inside)).
* **An edge crosses the loop boundary**: a node inside the loop is connected directly to one outside it. Connect to the Loop itself instead.
* **The item count exceeds the maximum**: the run fails with "Loop ... resolved N items, which exceeds the maximum of 500. Reduce the source array (for example filter or page it) so the loop runs over fewer items."

## Related

* [Iterating over arrays](/guides/iterating-arrays) for end-to-end recipes.
* [Expressions and filters](/guides/expressions) for the template syntax.
