Loop Node
Takes an array out of the payload and sends the branch below it one item at a time. Each pass carries its own position in the run, and when the last item comes back the node fires a second port — done — with everything the loop collected. It is the node for “for each row, do this”.
Two ports, not one
- loop — fires once per item. Everything you want done per item hangs here.
- done — fires once, after the last iteration, with the accumulated results. Summaries, notifications, and “write the report” hang here.
What you configure
Iterable field
The field holding the array: data.items, or a template like {{payload.items}}. If it does not resolve to an array there is nothing to iterate and the loop finishes immediately.
Iteration timeout
5 to 300 seconds, 30 by default. If the loop-back signal has not arrived within it, the loop advances to the next item instead of waiting. Size it against the slowest thing in the branch — an HTTP call to a slow API, an approval that a human has to click.
On iteration error
| Policy | What happens | Pick it when |
|---|---|---|
| Timeout | Waits out the timeout, then advances | The default. A slow item is not a failed item. |
| Skip | Advances immediately | Bad rows are expected and the run should not drag. |
| Retry | Re-executes the same item, up to Max retries per item (1–10), then skips | The failure is transient — a rate limit, a flaky endpoint. |
| Stop | Halts the loop | Order matters and a gap would corrupt the result. |
What each port receives
Per iteration, on the loop port
{
"_meta": {
"iterable": false,
"count": 1,
"loopIndex": 2,
"loopTotal": 10,
"isFirst": false,
"isLast": false
},
"sku": "AB-99",
"qty": 3
}The item is spread at the top level, so the branch reads {{payload.sku}} and not {{payload.item.sku}}. An item that is not an object (a plain string, a number) arrives as { "value": … }.
loopIndex, loopTotal, isFirst and isLast are readable from templates — useful for “post a header on the first item” or “only notify on the last one”. Note that iterable stays false on purpose: one item is one object, so Filter, Limit and Aggregator downstream treat it as a single thing.
Once, on the done port
{
"_meta": {
"loopComplete": true,
"totalIterations": 10,
"iterable": true,
"iterateField": "results",
"count": 10
},
"results": [ … ]
}results is marked iterable, so the done branch can itself fan out — to write a summary row per result, for instance. Compare count against totalIterations to notice items that were skipped.
Gotchas
- The loop is sequential. One item at a time, by design — it is what makes the timeout and the error policy mean anything. For parallel fan-out, feed the array to nodes that accept an iterable payload directly.
- Everything in the branch is billed per item. An AI Node or a Vector Store query inside a 500-item loop is 500 calls.
- Plans cap the iterations — 50 on free, 5,000 on pro, 50,000 on enterprise. A longer array is truncated and reported, never rejected: the first N items run and the result says how many were left out. Refusing the whole job would mean a large but legitimate run never happens at all.
- Nothing hanging off done means the result is discarded. The accumulated
resultsarray only exists on that port.