Loops
Iterate any node over an array of items.
Any node in a flow can be configured to run in a loop — executing once per item in an array and collecting the results. This is done through the node's Loop configuration panel in the editor, without adding a separate loop node.
How it works
When loop-over is enabled on a node:
- Invect resolves the
loopOverexpression against the upstream data to get an array - The node executes once per item in that array
- Results are collected and packaged according to the
outputMode - The packaged output is passed to downstream nodes as a single value
The node behaves identically to a non-looping node from the perspective of downstream nodes — they just receive the collected output instead of a single execution's output.
Configuration
loopOver
A Nunjucks expression that resolves to the array to iterate. Evaluated against the node's incoming data.
{{ http_request.response.users }}
{{ fetch_issues.items }}
{{ manual_trigger.ids }}itemAs and indexAs
Variable names that become available in the node's parameter templates during each iteration.
itemAs: "user"
indexAs: "i"Inside the node's params you can then use:
{{ user.email }}
{{ user.name }}
{{ i }} // 0-based indexThe default item variable name is item if itemAs is not set.
Iteration context
Each iteration also exposes a _loop context object in templates:
| Variable | Description |
|---|---|
_loop.index | 0-based index |
_loop.iteration | 1-based iteration number |
_loop.first | true on the first iteration |
_loop.last | true on the last iteration |
_loop.total | Total number of items |
Processing {{ _loop.iteration }} of {{ _loop.total }}: {{ user.name }}Output modes
Control how the results from all iterations are packaged:
| Mode | Output |
|---|---|
array | Array of each iteration's output (default) |
first | Only the first iteration's output |
last | Only the last iteration's output |
concat | Concatenate string outputs into a single string |
object | Object keyed by a field from each iteration's output |
object mode
When using object output mode, set keyField to the field path that should become the key:
outputMode: "object"
keyField: "id"If each iteration outputs { id: "abc", name: "Alice" }, the result is:
{
"abc": { "id": "abc", "name": "Alice" },
...
}Concurrency
By default, iterations run sequentially (concurrency: 1). Increase this to run multiple iterations in parallel:
concurrency: 5 // run up to 5 iterations simultaneouslyMaximum concurrency is 50. Use parallel execution carefully with external APIs that have rate limits.
Empty array behaviour
Control what happens when loopOver resolves to an empty array or a non-array value:
| Setting | Behaviour |
|---|---|
error | Fail the node with an error (default) |
skip | Skip execution, output empty array |
single | Treat a non-array value as a single-item array |
Example
Send a Slack message for each item in a list returned by an upstream HTTP request:
- Add an
http.requestnode that returns{ users: [{ name: "Alice", channel: "C123" }, ...] } - Add a
slack.send_messagenode - Enable loop on the Slack node with:
loopOver:{{ http_request.response.users }}itemAs:useroutputMode:array
- In the Slack node's params, set message to
{{ user.name }} has been notifiedand channel to{{ user.channel }}
The Slack node will execute once per user, and downstream nodes will receive an array of all send results.