> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ellomas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Loops

> Iterate over arrays and run nested steps for each element.

# Loops

The `loop` step iterates over an array from the state bag and runs nested steps for each element. It is useful for processing lists, validating each item in a collection, or generating dynamic reports.

## Basic Loop

```yaml theme={null}
- name: process-items
  type: loop
  foreach: item_list, item
  steps:
    - name: print-item
      type: print
      message: "Processing: {{ item }}"
```

The `foreach` format is `list_variable, item_variable`. The first part references an array in the state bag, the second part is the name each element gets during iteration.

## Loop Variables

During each iteration, these variables are available inside the loop body:

| Variable | Description                                                       |
| -------- | ----------------------------------------------------------------- |
| `item`   | Current element value (name matches the second part of `foreach`) |
| `index`  | Zero-based loop index                                             |

```yaml theme={null}
- name: list-users
  type: loop
  foreach: users, user
  steps:
    - name: show
      type: print
      message: "[{{ index }}] {{ user.name }} ({{ user.email }})"
```

## Nested Steps

A loop body can contain multiple steps of any type:

```yaml theme={null}
- name: process-orders
  type: loop
  foreach: orders, order
  steps:
    - name: fetch-details
      type: http
      request:
        method: GET
        url: /orders/{{ order.id }}

    - name: log
      type: print
      message: "Order {{ order.id }}: ${{ order.total }}"

    - name: assert-valid
      type: db
      query: "SELECT id FROM orders WHERE id = {{ order.id }}"
      assert:
        - ["$[0].id", "not_null"]
```

## Extracting an Array for Looping

You will typically extract an array from a previous step:

```yaml theme={null}
- name: fetch-staff
  type: http
  request:
    method: GET
    url: /staff
  extract:
    staff_list: $.data.items

- name: list-each
  type: loop
  foreach: staff_list, staff
  steps:
    - name: print-member
      type: print
      message: "{{ staff.firstName }} {{ staff.lastName }} ({{ staff.email }})"
```

### From Shell

```yaml theme={null}
- name: get-list
  type: shell
  command: 'echo "{\"items\": [\"apple\", \"banana\", \"cherry\"]}"'
  extract:
    fruit_list: $.items

- name: iterate
  type: loop
  foreach: fruit_list, fruit
  steps:
    - name: shout
      type: print
      message: "{{ upper fruit }}"
```

### From Database

```yaml theme={null}
- name: query-users
  type: db
  query: "SELECT id, name FROM users LIMIT 10"
  extract:
    users: "$"

- name: process-each
  type: loop
  foreach: users, user
  steps:
    - name: check-user
      type: db
      query: "SELECT verified FROM users WHERE id = {{ user.id }}"
      assert:
        - ["$[0].verified", "eq", true]
```

## Auto-Cleanup

When the loop finishes, the item variable and `index` are automatically deleted from the state bag. This prevents them from leaking into steps after the loop:

```yaml theme={null}
- name: loop-step
  type: loop
  foreach: items, item
  steps:
    - name: show
      type: print
      message: "{{ item }}"

- name: after-loop
  type: print
  message: "{{ item }}"   # ← This will be empty — item was cleaned up
```

## What's Next?

* Compose workflows across files with [workflow chaining](/replay/guides/workflow-chaining)
* Run workflows in parallel with [parallel execution](/replay/guides/parallel-execution)
