Skip to main content
The Loop step runs a group of steps repeatedly — once for each item in a list, a set number of times, or for as long as a condition holds. It is a container: the steps that repeat live inside it on the canvas, and everything after the loop connects to its bottom edge. Iterations run one after another, never in parallel. Each one finishes before the next begins, so a later iteration can read what earlier ones produced. When the items are independent and you want them at the same time, use the Parallel step instead.

Setting it up

Drop a Loop node on the canvas and it appears as an empty container with a + inside it. That + adds the first step of the body; the handle on the container’s bottom edge is where the workflow continues once the loop is done. The inspector has one required choice — Repeat — and the field below it changes to match. An empty list runs zero iterations and the workflow carries on — that is not an error.

Optional settings

Stop early when — a condition checked after every iteration. When it is true the loop ends. The iteration that satisfied it still counts and still contributes its result. Maximum iterations — a ceiling. While-loops default to 100 if you leave it blank, since a condition that never goes false would otherwise run forever. Every mode is capped at 10,000 regardless. If a step inside the loop fails

Referencing data

Inside the loop body: After the loop: n3 stands for the loop’s own step id — replace it with yours. The inspector prints the right one for you.
To test how many results you have so far, use {{ $count(n3.results) }}, not $exists(). JSONata treats an empty array as nothing, so $exists() on a loop that has not finished an iteration yet will mislead you.

An iteration’s result is its last step’s output

Each entry in results is whatever the final step of the body produced. If your body ends with a Wait step, you will get the wait’s output rather than the useful work before it — put the step whose output you want last.

Looking back at earlier iterations

Because results is readable from inside the body, a step can use everything that came before it, not just the previous pass:
Building a running total works the same way:
The run context is shared between iterations, so a step’s output from the previous pass is still there when the next one starts. That is useful, but it means a step reading another step of the same body will silently pick up a stale value rather than failing if that step has not run yet this iteration. Guard with $exists() where it matters.

Waiting inside a loop

A Wait step inside the body suspends the whole run and resumes on the next iteration exactly where it left off — the item being processed and everything collected so far survive the pause. That makes while mode plus a Wait the way to poll something until it is ready:
  1. Wait — pause between checks
  2. HTTP API — ask for the current status
  3. Loop condition — {{ check_status.state != 'done' }}
Run this asynchronously. A synchronous run only serves waits up to 5 seconds each and 15 seconds in total, and fails past that — which a poll loop reaches almost immediately.

Nesting

A loop can contain another loop. The inner one runs completely on each pass of the outer one, and starts collecting fresh results each time. In the outer loop’s results, each entry is the inner loop’s summary — its results, iterations, and errors.

When to use it

Considerations

  • Iterations are serial. Ten items each taking two seconds takes twenty seconds. For concurrency, use the Parallel step.
  • Body step data holds the last iteration only. After the loop, a body step’s own output is whatever the final pass left. The full history is in results.
  • The body must be self-contained. A step inside the loop cannot also be reachable from after it; the workflow will not save. Steps that repeat go in the container, steps that run once go after it.
  • Output steps cannot go inside a loop. An Output step ends the workflow, which is ambiguous mid-iteration. Put it after the loop.
  • A loop with no steps inside does nothing and the workflow continues — it will not fail the run.