Loops (Loop / Iterator Node)
The Loop node (also called the Iterator node) enables you to iterate over a list of items, running a sub-graph of nodes once for each item. It's the key to building bulk processing pipelines — processing 100 URLs, 1000 content prompts, or a batch of log entries.
Concept
Without the Loop node, an agent node runs exactly once per workflow execution. With a Loop node, you define a list of items, and everything downstream of the loop runs once per item:
This processes three topics, running the writer agent three times — once for "topic1", once for "topic2", once for "topic3". The Output node receives a JSON array of all three results.
Configuration
| Field | Type | Description |
|---|---|---|
| Name / Label | string | Canvas display name — also determines expression prefix {{name.current_item}} |
| Items Expression | string | Expression or literal that evaluates to a list |
| Max Iterations | int | Safety cap (default: 1000). Execution stops if list is longer. |
Items Expression
The items_expression must resolve to a Python list. You can provide:
Literal List
["topic 1", "topic 2", "topic 3"]
From Trigger Output (JSON Array)
If the trigger's input is a JSON array:
{{trigger.output}}
TARX parses the expression value as JSON if it starts with [.
Example trigger input:
["https://example.com/page1", "https://example.com/page2", "https://example.com/page3"]
From Upstream Agent (JSON Array Output)
If an upstream agent outputs a JSON array:
{{list_generator.output}}
Example agent output that generates a list:
["Write about quantum computing", "Write about AI in medicine", "Write about neural networks"]
Inline List from Agent
An agent can generate the list dynamically — just instruct it to return a JSON array:
# Agent: topic_generator
# System prompt: Generate a list of 10 blog topics about the given subject.
# Respond with ONLY a JSON array of strings, no prose.
# Output: ["Topic 1", "Topic 2", ..., "Topic 10"]
Then use {{topic_generator.output}} as the items expression. If the agent wraps the array in extra text, add a Transform node to extract the array before the loop.
Loop Variables
Inside the loop body (nodes connected downstream of the loop node), use these expressions:
| Expression | Type | Description |
|---|---|---|
{{loop_name.current_item}} | string | The current item being processed |
{{loop_name.index}} | int | Current 0-based index (0, 1, 2, ...) |
Example — loop named content_loop:
# Agent input field:
You are writing content piece number {{content_loop.index}} (starting from 0).
Topic: {{content_loop.current_item}}
Write a 200-word introduction for this topic.
Make it unique and distinct from the other pieces in the series.
Loop Output
After the loop completes all iterations, its output is a JSON array of all the results collected from the downstream nodes:
| Expression | Value |
|---|---|
{{loop_name.output}} | ["result for item 0", "result for item 1", ...] |
This output is available in nodes connected after the loop node (not inside the loop body).
Building a Loop Workflow
Step-by-Step: Bulk Content Generator
Let's build a workflow that generates 5 blog post introductions.
Step 1: Trigger
- Type: Manual
- Default Input:
["AI in healthcare", "Quantum computing basics", "The future of remote work", "Sustainable technology", "Blockchain in supply chain"]
Step 2: Loop Node
- Name:
content_loop - Items Expression:
{{trigger.output}} - Max Iterations: 10
Step 3: Writer Agent (inside loop)
- Agent:
writer - Input:
Write a 150-word blog post introduction about the following topic.
Be engaging and hook the reader in the first sentence.
Topic: {{content_loop.current_item}}
This is introduction {{content_loop.index + 1}} of 5 in a series.
Step 4: Output Node
- Value:
{{content_loop.output}}
Connect the nodes:
- Trigger → Loop Node → Writer Agent → Output Node
When executed, this runs the writer agent 5 times (once per topic) and collects all 5 introductions in the output as a JSON array.
Connecting Nodes Inside vs. Outside the Loop
Inside the loop body: Connect directly after the Loop node. These nodes run once per item.
Outside the loop body: Connect after the last node in the loop body's sub-chain. These nodes run once after the entire loop completes.
Nodes that are connected in a chain starting from the Loop node's output are considered "inside" the loop and run per iteration. The Loop node's final output is emitted after all iterations complete, and nodes connected to that output run once.
The executor detects this by topological analysis of the graph.
Nested Loops
You can nest Loop nodes for matrix processing (e.g., for each language × for each topic):
Outer loop variables: {{languages.current_item}} → "en", "es", "fr"
Inner loop variables: {{topics.current_item}} → each topic
Agent input:
Translate this blog intro to {{languages.current_item}}:
Topic: {{topics.current_item}}
A 3-item outer loop × 5-item inner loop = 15 agent executions. At 100×100, that's 10,000 LLM calls. Be mindful of cost and the max_iterations safety limit.
Processing Lists from Webhooks
A common pattern: a webhook delivers a list of items to process.
Webhook payload:
{
"items": [
{"id": "1", "url": "https://..."},
{"id": "2", "url": "https://..."}
]
}
Workflow:
- Webhook Trigger (Payload Path:
$.items→{{trigger.output}}= JSON array of items) - Loop Node (Items Expression:
{{trigger.output}}) - Agent:
{{loop.current_item}}gives each item object as JSON - Agent processes each item
Collecting and Using Loop Results
After the loop, the output is a JSON array. To use it meaningfully:
Pass to a Summary Agent
# Summary agent input:
Here are the results from processing {{total_items}} items:
{{content_loop.output}}
Please provide a brief executive summary of all the items.
Post Each Result to an API
Add an http_request node inside the loop body to post each item's result as it's generated:
Agent (process {{loop.current_item}})
→ http_request node POST https://api.myapp.com/results
body: {{agent.output}}
Filter the Results After the Loop
After the loop, use a Filter node to keep only the results you want, or a Transform node to reshape the collected array — both without writing code:
Loop → Filter keep items where len(item) > 100
→ Transform JSONPath to extract/reshape
Performance and Limits
| Consideration | Details |
|---|---|
| Execution order | Iterations execute sequentially, not in parallel. Item 2 starts after item 1 completes. |
| Max iterations | Default 1000. Set lower for safety. |
| Cost | Each iteration = one or more LLM calls. 100 iterations × $0.01/call = $1.00 in LLM cost. |
| Time | Each iteration adds latency. 100 iterations × 5 seconds = ~8 minutes total. |
| Partial failure | If one iteration fails, the loop stops at that point. Completed iterations' results are preserved. |
Loops are best for one-time bulk processing. For high-frequency repeated operations (polling, real-time streams), use Schedule triggers calling lightweight workflows.
Example: URL Scraper Pipeline
A complete bulk scraping workflow:
Trigger: Manual
Input: ["https://blog.anthropic.com/", "https://openai.com/blog", "https://deepmind.com/blog"]
Loop: scraper_loop
Items: {{trigger.output}}
Agent: scraper (web_scraper capability)
Input:
Scrape this URL and extract the titles of the 5 most recent blog posts.
Return as JSON array of strings.
URL: {{scraper_loop.current_item}}
Agent: formatter
Input:
Format these blog post titles as a markdown list with the source URL:
Source: {{scraper_loop.current_item}}
Titles: {{scraper.output}}
Output: {{scraper_loop.output}}
This visits 3 blog URLs and returns a formatted list of recent posts from each.