HeliosHELIOS DOCS
WorkflowsControl nodes

Loop Node

Iteration node that processes arrays sequentially or in parallel with configurable execution modes

Loop Node

The Loop node enables iteration in your workflows. It can iterate over arrays of data (forEach) or repeat execution a specified number of times (forN). The node supports both sequential and parallel execution modes for optimal performance.

Configuration

Input Schema

The Loop node accepts one of two input modes:

forEach Mode

FieldTypeRequiredDescription
forEachJsonValue[]YesArray of items to iterate over
forNundefinedNoMust be undefined in forEach mode

forN Mode

FieldTypeRequiredDescription
forNnumberYesNumber of iterations (minimum 1)
forEachundefinedNoMust be undefined in forN mode

Configuration Schema

FieldTypeRequiredDescription
mode"sequential" | "parallel"YesExecution mode for iterations

Output Schema

FieldTypeDescription
totalIterationsnumberTotal number of iterations executed
iterationsJsonValue[]Array of results from each iteration

Basic Usage

Array Iteration (forEach)

# Process a list of users
- id: process_users
  type: loop
  input:
    forEach: "{{ users }}"
  configuration:
    mode: "sequential"

Count-based Iteration (forN)

# Retry an operation 3 times
- id: retry_operation
  type: loop
  input:
    forN: 3
  configuration:
    mode: "sequential"

Advanced Examples

# Process files in parallel for speed
- id: process_files_parallel
  type: loop
  input:
    forEach: "{{ uploadedFiles }}"
  configuration:
    mode: "parallel"

Use parallel mode when operations are independent and can benefit from concurrent execution. Perfect for file processing, image resizing, or API calls that don't depend on each other.

# Process orders one by one to maintain inventory state
- id: process_orders
  type: loop
  input:
    forEach: "{{ orders }}"
  configuration:
    mode: "sequential"

Use sequential mode when order matters or when operations depend on shared state. Essential for inventory management, account balance updates, or any workflow requiring consistency.

# Process data in batches
- id: create_batches
  type: loop
  input:
    forN: "{{ Math.ceil(data.length / batchSize) }}"
  configuration:
    mode: "sequential"

Use forN mode with calculated iterations for batch processing. Ideal for handling large datasets by processing them in manageable chunks.

Use Cases

Transform each item in an array:

# Resize multiple images
- id: resize_images
  type: loop
  input:
    forEach: "{{ images }}"
  configuration:
    mode: "parallel"
  # Child nodes would access {{ loop.current }} for each image

Perfect for applying the same operation to multiple items like image processing, data cleaning, or format conversion.

Fetch all pages of data:

# Fetch all pages from paginated API
- id: fetch_all_pages
  type: loop
  input:
    forN: "{{ totalPages }}"
  configuration:
    mode: "sequential"
  # Child nodes would use {{ loop.index }} for page number

Ideal for systematically fetching all data from paginated APIs where you need to iterate through page numbers.

Process large datasets in chunks:

# Process users in batches of 100
- id: batch_process_users
  type: loop
  input:
    forN: "{{ Math.ceil(users.length / 100) }}"
  configuration:
    mode: "sequential"

Essential for handling large datasets by breaking them into manageable chunks to avoid memory issues or API rate limits.

Implement retry mechanisms:

# Retry failed operations
- id: retry_with_backoff
  type: loop
  input:
    forN: 5
  configuration:
    mode: "sequential"
  # Child nodes implement exponential backoff

Build robust workflows by automatically retrying failed operations with configurable attempts and backoff strategies.

Execute independent operations concurrently:

# Send notifications to multiple channels
- id: send_notifications
  type: loop
  input:
    forEach: "{{ notificationChannels }}"
  configuration:
    mode: "parallel"

Maximize throughput by executing independent operations simultaneously, perfect for notifications, file uploads, or API calls.

Loop Context Variables

Available when iterating over arrays:

  • {{ loop.current }} - Current item being processed
  • {{ loop.index }} - Zero-based index of current iteration
  • {{ loop.isFirst }} - True if this is the first iteration
  • {{ loop.isLast }} - True if this is the last iteration
  • {{ loop.total }} - Total number of items

Perfect for array processing where you need access to both the item and its position.

Available when using count-based iteration:

  • {{ loop.index }} - Zero-based index of current iteration (0 to N-1)
  • {{ loop.iteration }} - One-based iteration number (1 to N)
  • {{ loop.isFirst }} - True if this is the first iteration
  • {{ loop.isLast }} - True if this is the last iteration
  • {{ loop.total }} - Total number of iterations

Ideal for retry logic, pagination, or any scenario requiring a specific number of iterations.

Best Practices

Use Sequential Mode When:

  • Order of execution matters
  • Operations modify shared state
  • Each iteration depends on previous results
  • Memory usage needs to be controlled
# Sequential for state-dependent operations
- id: process_transactions
  type: loop
  input:
    forEach: "{{ transactions }}"
  configuration:
    mode: "sequential"  # Maintain account balance consistency

Use Parallel Mode When:

  • Operations are independent
  • Performance is critical
  • No shared state modifications
  • I/O bound operations
# Parallel for independent operations
- id: validate_emails
  type: loop
  input:
    forEach: "{{ emailList }}"
  configuration:
    mode: "parallel"  # Each validation is independent

Key optimization strategies:

  • Batch size: For large arrays, consider chunking data
  • Resource limits: Be mindful of memory and CPU usage
  • Timeouts: Implement timeouts for long-running operations
  • Error handling: Plan for partial failures in parallel mode
# Good: Controlled batch processing
- id: controlled_processing
  type: loop
  input:
    forEach: "{{ data.slice(0, 1000) }}"  # Limit batch size
  configuration:
    mode: "parallel"

Implement robust error resilience:

# Implement error resilience
- id: resilient_loop
  type: loop
  input:
    forEach: "{{ items }}"
  configuration:
    mode: "sequential"
  # Child nodes should include error handling
  • Always plan for partial failures in parallel mode
  • Use try-catch patterns in child nodes
  • Consider circuit breaker patterns for external API calls
  • Implement proper logging for debugging failed iterations

Integration Patterns

# Fetch data from multiple endpoints
- id: multi_endpoint_fetch
  type: loop
  input:
    forEach: "{{ endpoints }}"
  configuration:
    mode: "parallel"

# Child HTTP node
- id: fetch_endpoint
  type: http
  input:
    url: "{{ loop.current.url }}"
    method: "GET"

Perfect for parallel API calls, batch data fetching, and distributed service communication.

# Process multiple prompts
- id: ai_batch_processing
  type: loop
  input:
    forEach: "{{ prompts }}"
  configuration:
    mode: "sequential"  # Respect rate limits

# Child AI node
- id: process_prompt
  type: ai
  input:
    prompt: "{{ loop.current }}"

Ideal for bulk content processing, batch analysis, and respecting AI provider rate limits.

# Send Slack messages to multiple channels
- id: broadcast_message
  type: loop
  input:
    forEach: "{{ channels }}"
  configuration:
    mode: "parallel"

# Child Slack node
- id: send_slack_message
  type: slack
  input:
    channel: "{{ loop.current }}"
    message: "{{ broadcastMessage }}"

Essential for multi-channel notifications, bulk email sending, and broadcast communications.

Nested Loops

# Outer loop: Process each user
- id: process_users
  type: loop
  input:
    forEach: "{{ users }}"
  configuration:
    mode: "sequential"

# Inner loop: Process each user's orders
- id: process_user_orders
  type: loop
  input:
    forEach: "{{ loop.current.orders }}"
  configuration:
    mode: "parallel"

Troubleshooting

Debugging Tips

# Add logging to track loop progress
- id: debug_loop
  type: loop
  input:
    forEach: "{{ items }}"
  configuration:
    mode: "sequential"

# Debug child node
- id: log_iteration
  type: script
  input:
    script: |
      console.log(`Processing item ${loop.index}: ${JSON.stringify(loop.current)}`);
      return loop.current;

The Loop node is essential for processing collections and implementing retry logic, making it a cornerstone of data processing workflows.

Last updated on