Skip to content

Loop Control


Looping over dict2items output produces annotations like (item={'key': 'timeout', 'value': 30}) — readable enough for a small example, genuinely noisy once items get bigger or more numerous. loop_control is the toolset for exactly that, plus two more genuinely useful controls: knowing your position in a loop, and slowing it down.

label: Cleaner Output For Complex Items

loop_control.label replaces the full item dump in output with whatever you specify instead:

label_demo.yaml
- name: "Apply settings"
  ansible.builtin.debug:
    msg: "Would set {{ item.key }} to {{ item.value }}"
  loop: "{{ settings | dict2items }}"
  loop_control:
    label: "{{ item.key }}"
ok: [ubuntu] => (item=timeout) => {
    "msg": "Would set timeout to 30"
}

Compare that (item=timeout) to the full (item={'key': 'timeout', 'value': 30}) — much easier to scan, especially once a loop’s items carry several fields.

There’s a second, sharper reason to use this beyond tidiness: if an item ever contains something sensitive — a password field in a user record, say — label is one of the ways how you keep that value out of the loop’s own output annotation entirely, showing only the field you explicitly choose.

index_var: Knowing Which Iteration You’re On

index_var names a variable holding the current iteration’s position (starting at 0):

- name: Dict Loop Demo
  hosts: ubuntu
  vars:
    users:
      - alice
      - bob
  tasks:
    - name: "User Processing"
      ansible.builtin.debug:
        msg: "Processing user '{{ item }}' at #{{ user_index }}"
      loop: "{{ users }}"
      loop_control:
        index_var: user_index
TASK [User Processing] *********************
ok: [ubuntu] => (item=alice) => {
    "msg": "Processing user 'alice' at #0"
}
ok: [ubuntu] => (item=bob) => {
    "msg": "Processing user 'bob' at #1"
}

Useful for numbering output clearly, or for conditionally acting only on a specific position — when: user_index == 0 for “just the first item,” for instance.

pause: Slowing Down Between Iterations

pause inserts a delay, in seconds, between each iteration:

loop_control:
  pause: 2

Worth reaching for when a loop is doing something that shouldn’t be hammered too quickly — calling a rate-limited API, or deliberately spacing out a rolling action across several hosts, for instance. Not something to add by default; only when there’s a genuine reason to throttle.

Combining loop_control Options

All three compose freely:

- name: Dict Loop Demo
  hosts: ubuntu
  vars:
    users:
      - name: alice
        age: 20
      - name: bob
        age: 30
  tasks:
    - name: "Processing users"
      ansible.builtin.debug:
        msg: "Working on user '{{ item.name }}', age={{ item.age }}"
      loop: "{{ users }}"
      loop_control:
        label: "{{ item.name }}"
        index_var: user_index
        pause: 1

Best Practices

  • Use label any time a loop’s items are large or contain sensitive fields — cleaner output, and a genuine safeguard against leaking something into logs that shouldn’t be there.
  • Use index_var when position matters — numbering, or targeting a specific iteration by its place in the list.
  • Only use pause when there’s a real reason to throttle — a rate limit, a deliberate rollout pace — not as a default habit.
Last updated on