Documentation Index
Fetch the complete documentation index at: https://docs.dualship.run/llms.txt
Use this file to discover all available pages before exploring further.
The loop node iterates over data, executing a set of nodes for each iteration. It supports three modes: iterating over arrays, running a fixed count, or looping while a condition is true.
Configuration
{
"id": "process_orders",
"type": "loop",
"config": {
"items": "{{request.body.orders}}",
"as": "order",
"index": "i",
"do": ["validate_order", "process_order"],
"concurrent": false
}
}
Config Fields
| Field | Type | Required | Default | Description |
|---|
items | string | * | - | Template resolving to an array |
count | number/string | * | - | Number of iterations or template |
while | string | * | - | Condition to check each iteration |
max | number | ** | - | Maximum iterations (required for while) |
as | string | No | "item" | Variable name for current item |
index | string | No | "index" | Variable name for current index |
do | string[] | Yes | - | Node IDs to execute each iteration |
concurrent | boolean | No | false | Run iterations in parallel |
* Must specify exactly one of: items, count, or while
** Required when using while mode
Loop Modes
Items Mode
Iterate over an array:
{
"id": "send_emails",
"type": "loop",
"config": {
"items": "{{users}}",
"as": "user",
"index": "i",
"do": ["send_email"]
}
}
Inside the loop, access:
{{user}} - Current array element
{{i}} - Current index (0-based)
Count Mode
Run a fixed number of times:
{
"id": "retry_request",
"type": "loop",
"config": {
"count": 3,
"index": "attempt",
"do": ["make_request", "check_success"]
}
}
Count can be a template:
{
"count": "{{request.body.quantity}}"
}
While Mode
Loop while a condition is true:
{
"id": "paginate",
"type": "loop",
"config": {
"while": "{{has_more_pages}} == true",
"max": 100,
"do": ["fetch_page", "check_more"]
}
}
The max field is required to prevent infinite loops.
Output
{
"iterations": 5,
"results": [
{ "index": 0, "output": { ... } },
{ "index": 1, "output": { ... } },
{ "index": 2, "output": { ... } },
{ "index": 3, "output": { ... } },
{ "index": 4, "output": { ... } }
],
"completed": true,
"error": null
}
| Field | Type | Description |
|---|
iterations | number | Total iterations completed |
results | array | Output from each iteration |
completed | boolean | Whether loop finished normally |
error | string | Error message if loop failed |
Context Variables
During each iteration, these variables are available:
| Variable | Description |
|---|
{{item}} (or custom as) | Current item (items mode) or iteration number (count mode) |
{{index}} (or custom name) | Zero-based iteration index |
Example Access
{
"id": "process_item",
"type": "http",
"config": {
"method": "POST",
"url": "https://api.example.com/items",
"body": {
"item_id": "{{order.id}}",
"iteration": "{{i}}"
}
}
}
Examples
Process Array Items
{
"id": "process_all_orders",
"type": "loop",
"config": {
"items": "{{fetch_orders.output.body}}",
"as": "order",
"do": ["validate_order", "save_order"]
}
}
Concurrent Processing
Process items in parallel for better performance:
{
"id": "send_notifications",
"type": "loop",
"config": {
"items": "{{subscribers}}",
"as": "subscriber",
"do": ["send_notification"],
"concurrent": true
}
}
Fetch all pages from a paginated API:
[
{
"id": "init_pagination",
"type": "set",
"config": {
"key": "page",
"value": 1
}
},
{
"id": "init_has_more",
"type": "set",
"config": {
"key": "has_more",
"value": true
}
},
{
"id": "fetch_all_pages",
"type": "loop",
"config": {
"while": "{{has_more}} == true",
"max": 50,
"do": ["fetch_page", "update_pagination"]
}
}
]
Retry Pattern
Retry a request up to 3 times:
{
"id": "retry_api_call",
"type": "loop",
"config": {
"count": 3,
"index": "attempt",
"do": ["make_request", "check_if_should_retry"]
}
}
Accessing Loop Results
After the loop, access results by index:
{
"id": "summarize",
"type": "transform",
"config": {
"output": {
"total_processed": "{{process_all_orders.output.iterations}}",
"first_result": "{{process_all_orders.output.results[0]}}",
"all_results": "{{process_all_orders.output.results}}"
}
}
}
Nested Data Access
When iterating over objects with nested data:
{
"id": "process_nested",
"type": "loop",
"config": {
"items": "{{data.users}}",
"as": "user",
"do": ["process_user"]
}
}
Inside process_user:
{{user.name}} -> Access user's name
{{user.address.city}} -> Access nested properties
{{index}} -> Current iteration index
- Use
concurrent: true for independent operations
- Set reasonable
max for while loops to prevent runaway execution
- Batch operations when possible instead of individual API calls
- Limit iterations - very large loops can impact performance