Skip to main content

Loop Node 🔁

Repeats execution of a sub-path while a condition is true, or iterates over a collection.

Node type: loopNode Category: Flow Control Actor: loopNode (1 thread)


Description

The Loop Node enables repeated execution of a workflow path. It supports two loop types:

  • Standard Loop — repeats while a JUEL condition is true
  • Collection Loop — iterates over each item in an array variable

The loop body is the path of nodes connected after the Loop Node. Each iteration executes the body, then returns control to the Loop Node to check the condition again.


Properties

PropertyTypeRequiredDescription
loopExpressiontextConditionalJUEL condition for Standard Loop: ${count < 5}
loopVariabletextConditionalVariable name for the current item in Collection Loop
maxIterationsnumberNoSafety cap on maximum iterations (default: 100)

The loop type is inferred:

  • If loopExpression is set → Standard Loop
  • If a collection variable is configured → Collection Loop

Standard Loop

Repeats while the expression evaluates to true. The loop body executes, then the condition is re-evaluated.

loopExpression: ${retryCount < 3}
maxIterations: 5

Pattern:

[Set Variable: retryCount = 0]

[Loop Node: ${retryCount < 3}]
↓ (loop body)
[Service Task: Call API]
↓ successFlow
[Loop Node: exit] ← connect back to Loop Node exit
↓ (on exit)
[Continue]
info

Use a Set Variable node inside the loop body to increment the counter: retryCount → {retryCount + 1}. The loop exits when retryCount reaches 3.


Collection Loop (Multi-Instance)

Iterates over each item in an array. The loop body executes once per item. The current item is available as the loopVariable.

collection: orderItems
loopVariable: currentItem
[SQL: Fetch all pending orders → {orderList}]

[Loop: collection=orderList, variable=currentOrder]

[Service Task: Process order {currentOrder.id}]

[AI Task: Generate confirmation for {currentOrder.customerEmail}]

[Service Task: Send Email to {currentOrder.customerEmail}]
↓ (loop back automatically)
[After loop: Log completion]

Each iteration has access to:

  • {currentOrder} — the current item (object or primitive)
  • {currentOrder.id} — properties of the current item if it's an object
  • {loopIndex} — zero-based index of the current iteration (built-in)

Outputs

After the loop completes:

VariableTypeDescription
{loopIndex}numberIndex of the last completed iteration
{loopCount}numberTotal number of iterations completed
Any variables set in loop bodyLast iteration's values are retained

Connections

ConnectionDescription
sequenceFlow (incoming)Arrives from previous node
sequenceFlow (loop body)Goes into the loop body
sequenceFlow (exit)Goes to the node after the loop
Loop-back connectionFrom end of loop body back to the Loop Node (engine-managed)

The designer shows the Loop Node with two outgoing paths: one entering the loop body and one exiting when the loop completes.


Max Iterations Safety

Always set maxIterations to prevent infinite loops in production:

maxIterations: 100

If the loop reaches maxIterations before the exit condition is met, the node fails with a LOOP_LIMIT_EXCEEDED error.


Example: Retry with Backoff

[Set Variable: retryCount=0, lastError='']

[Loop Node: ${retryCount < 3 && lastError != 'SUCCESS'}]

[Service Task: Call Payment API]
↓ errorFlow
[Set Variable: retryCount={retryCount+1}, lastError='FAILED']
↓ (wait)
[Script Task: sleep 1 second * retryCount]
↓ (loop back)
[Continue after loop]

Example: Process Collection in Batches

[SQL: Fetch unprocessed items → {itemList}]

[Loop: collection=itemList, variable=item, maxIterations=500]

[Service Task: POST to external API with {item.id}]
↓ successFlow
[SQL: UPDATE items SET processed=true WHERE id={item.id}]
↓ (loop back)
[Log: {loopCount} items processed]

Best Practices

  • Always set maxIterations — it prevents runaway loops consuming all engine threads
  • For collection loops, ensure the collection variable is an array (validate with Script Task or If/Else)
  • Use a Set Variable node at the start of the loop body if you need loop-specific variables
  • For heavy per-item processing, consider whether the items can be processed in parallel using Split/Join instead
  • Long-running loops should have a timeout set on the Loop Node itself