Skip to content

Looping Over List of Dictionaries


A loop’s items don’t have to be plain values like "apple". In practice, they’re very often dictionaries — each iteration carrying several related pieces of data at once, not just one.

Looping Over A List Of Dictionaries

loop:
  - name: alice
    role: admin
  - name: bob
    role: viewer

Each item in this loop is now a small dictionary, with two fields instead of one plain value.

Accessing Fields With item['key']

Bracket notation, consistent with every other dictionary access in this course:

dict_loop.yaml
- name: Dict Loop Demo
  hosts: servers
  tasks:
    - name: Print user info
      ansible.builtin.debug:
        msg: "{{ item['name'] }} has role {{ item['role'] }}"
      loop:
        - name: alice
          role: admin
        - name: bob
          role: viewer
ok: [ubuntu] => (item={'name': 'alice', 'role': 'admin'}) => {
    "msg": "alice has role admin"
}
ok: [ubuntu] => (item={'name': 'bob', 'role': 'viewer'}) => {
    "msg": "bob has role viewer"
}

A Realistic Example: Creating Multiple Users

Real playbooks loop over a variable, not an inline list written directly into the task — exactly the same separation-of-data-from-logic principle from the variables section, now applied to loop data:

create_users.yaml
- name: Create Users
  hosts: servers
  vars:
    users:
      - name: alice
        role: admin
      - name: bob
        role: viewer
      - name: carol
        role: editor
  tasks:
    - name: "Report user creation:"
      ansible.builtin.debug:
        msg: "Would create user '{{ item['name'] }}' with role '{{ item['role'] }}'"
      loop: "{{ users }}"

In a real deployment, that debug task would be ansible.builtin.user, actually creating each account — the loop mechanics controlling which users get processed are identical either way.

A Gotcha: Missing Keys Across Items

Real data isn’t always perfectly consistent. What happens when one entry is missing a key another one has?

loop:
  - name: alice
    role: admin
  - name: bob
msg: "{{ item['name'] }} has role {{ item['role'] }}"

alice’s iteration succeeds fine. bob’s fails — there’s no role key on that dictionary at all, and accessing a genuinely missing dictionary key with item['role'] raises an error rather than quietly returning something empty. Ansible runs every item in the loop regardless — a failure on one iteration doesn’t stop the rest from being attempted — but the task as a whole is still reported failed once any single iteration fails.

The fix is exactly the filter you’d expect from the manipulating-data section:

msg: "{{ item['name'] }} has role {{ item['role'] | default('unknown') }}"
alice has role admin
bob has role unknown

| default(...) handles a missing key here exactly the way it handled a missing variable back in that chapter — the mechanism is identical, just applied to a dictionary key inside a loop instead of a standalone variable.

Best Practices

  • Use bracket notation (item['key']) consistently, exactly as recommended for facts and every other dictionary access in this course.
  • Loop over a variable, not an inline list, in anything beyond a quick throwaway example — keep the data separate from the task logic, the same way vars_files and host_vars kept configuration separate from playbook structure.
  • Pair item['field'] with | default(...) whenever the entries in a loop’s list might not all share exactly the same keys — a single missing key shouldn’t have to fail an entire task’s worth of otherwise-fine iterations.
Last updated on