Skip to content

Looping Over a Dictionary


Back in the manipulating-data section, dict2items got a light forward mention: “genuinely useful once loops enter the picture.” This is that moment.

Why You Can’t Just Loop Over A Dict Directly

loop: expects a list. Hand it a dictionary directly, and you’d only get its keys, one at a time — the values are left behind, reachable only through a separate lookup inside the task. Workable, but awkward: you’d be reconstructing the key/value pairing by hand that the dictionary already had.

Using dict2items To Loop Over A Dictionary

dict2items, from the manipulating-data section, converts a dictionary into exactly the shape a loop wants — a list of key/value pairs, both available together on each iteration:

dict_loop.yaml
- name: Dict Loop Demo
  hosts: servers
  vars:
    settings:
      timeout: 30
      retries: 3
      verbose: true
  tasks:
    - name: "Print settings"
      ansible.builtin.debug:
        msg: "{{ item.key }} = {{ item.value }}"
      loop: "{{ settings | dict2items }}"
ok: [ubuntu] => (item={'key': 'timeout', 'value': 30}) => {
    "msg": "timeout = 30"
}
ok: [ubuntu] => (item={'key': 'retries', 'value': 3}) => {
    "msg": "retries = 3"
}
ok: [ubuntu] => (item={'key': 'verbose', 'value': True}) => {
    "msg": "verbose = True"
}

Accessing key And value

item.key and item.value are both safe as plain dot access — dict2items always produces exactly these two field names, with no risk of the dot-notation trap from the facts chapter. Bracket notation (item['key'], item['value']) works identically, and stays consistent with this course’s general recommendation if you’d rather default to it everywhere.

A Realistic Example: Applying Multiple Settings

This is the natural counterpart to the previous chapter’s user-creation example — but notice the shape of the source data is different, and that difference is the whole reason to reach for dict2items in the first place. The users example needed multiple fields per entry (name and role together), which is naturally a list of dictionaries. This settings example is fundamentally just key maps to value, one pair at a time — a plain dictionary is the more natural shape for that, and dict2items is what turns it into something loopable without losing anything.

- name: "Apply settings"
  ansible.builtin.debug:
    msg: "Would set {{ item.key }} to {{ item.value }}"
  loop: "{{ settings | dict2items }}"

Renaming Keys With dict2items’s Arguments

If key/value isn’t descriptive enough — especially if you’re nesting more than one dict2items-based loop and need to tell their fields apart — rename them directly:

loop: "{{ settings | dict2items(key_name='setting', value_name='setting_value') }}"
msg: "{{ item.setting }} = {{ item.setting_value }}"

Same data, clearer field names — worth doing the moment item.key/item.value on its own stops being obviously self-explanatory in context.

Best Practices

  • Reach for a plain dictionary plus dict2items when your data is naturally a flat key-to-value mapping. Reach for a list of dictionaries (previous chapter) when each entry genuinely needs more than one field of its own.
  • Use key_name/value_name to rename fields for clarity, especially once more than one dict2items-based loop shows up in the same playbook.
Last updated on