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:
- 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
dict2itemswhen 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_nameto rename fields for clarity, especially once more than onedict2items-based loop shows up in the same playbook.