AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible dict2items Filter: Convert Dictionaries to Lists (Guide)

By Luca Berton · Published 2024-01-01 · Category: database-automation

How to convert dictionaries to lists with Ansible dict2items filter and back with items2dict. Loop over dict key-value pairs.

Ansible's dict2items converts a dictionary into a list of key-value pairs you can loop over. items2dict does the reverse — turns a list back into a dictionary. Together they let you transform, filter, and iterate over data structures cleanly.

dict2items: Dictionary → List

vars:
  users:
    alice: admin
    bob: developer
    carol: viewer

tasks: - name: Show conversion ansible.builtin.debug: msg: "{{ users | dict2items }}" # Result: # [ # {"key": "alice", "value": "admin"}, # {"key": "bob", "value": "developer"}, # {"key": "carol", "value": "viewer"} # ]

See also: Ansible combine Filter: Merge Dictionaries & Override Defaults (Guide)

Loop Over a Dictionary

The primary use case — dictionaries aren't directly iterable in Ansible loops:

vars:
  packages:
    nginx: present
    postgresql: present
    cups: absent

tasks: - name: Manage packages ansible.builtin.package: name: "{{ item.key }}" state: "{{ item.value }}" loop: "{{ packages | dict2items }}"

items2dict: List → Dictionary

vars:
  user_list:
    - key: alice
      value: admin
    - key: bob
      value: developer

tasks: - name: Convert to dictionary ansible.builtin.set_fact: user_dict: "{{ user_list | items2dict }}" # Result: {"alice": "admin", "bob": "developer"}

See also: Ansible regex_search & regex_replace Filters: Pattern Matching Guide

Custom Key/Value Names

When your data uses different field names:

vars:
  servers:
    - hostname: web01
      ip: 10.0.1.50
    - hostname: web02
      ip: 10.0.1.51

tasks: - name: Convert with custom keys ansible.builtin.set_fact: server_map: "{{ servers | items2dict(key_name='hostname', value_name='ip') }}" # Result: {"web01": "10.0.1.50", "web02": "10.0.1.51"}

Same for dict2items:

vars:
  config:
    database_host: localhost
    database_port: 5432

tasks: - name: Convert with custom field names ansible.builtin.debug: msg: "{{ config | dict2items(key_name='param', value_name='setting') }}" # [{"param": "database_host", "setting": "localhost"}, ...]

Filter and Transform Dictionaries

Remove Entries

vars:
  all_services:
    nginx: enabled
    cups: disabled
    ssh: enabled
    bluetooth: disabled

tasks: - name: Get only enabled services ansible.builtin.set_fact: enabled_services: >- {{ all_services | dict2items | selectattr('value', 'equalto', 'enabled') | items2dict }} # Result: {"nginx": "enabled", "ssh": "enabled"}

Transform Values

vars:
  ports:
    http: "80"
    https: "443"
    ssh: "22"

tasks: # Open firewall for all ports - name: Open ports ansible.builtin.iptables: chain: INPUT protocol: tcp destination_port: "{{ item.value }}" jump: ACCEPT comment: "Allow {{ item.key }}" loop: "{{ ports | dict2items }}"

See also: Ansible ternary Filter: Inline If-Else Conditional in Jinja2 (Guide)

Nested Dictionaries

vars:
  environments:
    production:
      host: prod-db.example.com
      port: 5432
      replicas: 3
    staging:
      host: staging-db.example.com
      port: 5432
      replicas: 1

tasks: - name: Configure each environment ansible.builtin.template: src: db-config.j2 dest: "/etc/myapp/db-{{ item.key }}.conf" loop: "{{ environments | dict2items }}" # item.key = "production", item.value.host = "prod-db.example.com"

Merge Dictionaries

vars:
  defaults:
    port: 8080
    debug: false
    workers: 4
  overrides:
    port: 9090
    debug: true

tasks: - name: Merge configs (overrides win) ansible.builtin.set_fact: final_config: "{{ defaults | combine(overrides) }}" # Result: {"port": 9090, "debug": true, "workers": 4}

Real-World Examples

Create Users from Dictionary

vars:
  team:
    alice:
      uid: 1001
      groups: ['wheel', 'docker']
      shell: /bin/bash
    bob:
      uid: 1002
      groups: ['docker']
      shell: /bin/zsh

tasks: - name: Create team members ansible.builtin.user: name: "{{ item.key }}" uid: "{{ item.value.uid }}" groups: "{{ item.value.groups }}" shell: "{{ item.value.shell }}" loop: "{{ team | dict2items }}"

Configure DNS Records

vars:
  dns_records:
    web01.example.com: 10.0.1.50
    web02.example.com: 10.0.1.51
    db01.example.com: 10.0.2.10

tasks: - name: Add DNS entries to /etc/hosts ansible.builtin.lineinfile: path: /etc/hosts line: "{{ item.value }} {{ item.key }}" regexp: ".*{{ item.key }}$" loop: "{{ dns_records | dict2items }}"

Environment Variables from Dictionary

vars:
  app_env:
    DATABASE_URL: "postgresql://localhost/myapp"
    REDIS_URL: "redis://localhost:6379"
    SECRET_KEY: "{{ vault_secret_key }}"

tasks: - name: Write .env file ansible.builtin.copy: content: | {% for item in app_env | dict2items %} {{ item.key }}={{ item.value }} {% endfor %} dest: /opt/myapp/.env mode: '0600'

FAQ

When should I use dict2items vs just looping?

You need dict2items because Ansible's loop expects a list. Dictionaries can't be looped directly. dict2items converts {a: 1, b: 2} into [{key: a, value: 1}, {key: b, value: 2}] which loop can iterate.

Can I sort dict2items output?

Yes: {{ my_dict | dict2items | sort(attribute='key') }}. Dictionaries in Python 3.7+ preserve insertion order, but sorting ensures consistent ordering.

What's the difference between dict2items and the Jinja2 items() method?

dict2items returns a list of {key, value} objects. Jinja2's items() returns tuples. In Ansible, dict2items is preferred because it produces proper objects with named attributes.

How do I filter a dictionary by key pattern?

# Keep only keys starting with 'db_'
{{ my_dict | dict2items
   | selectattr('key', 'match', '^db_')
   | items2dict }}

Conclusion

dict2items and items2dict are the bridge between Ansible's dictionary data and its list-based looping. Use dict2items to iterate over dictionaries, selectattr to filter, and items2dict to rebuild. Together with combine for merging, they handle every dictionary transformation pattern.

Related Articles

Ansible map vs selectattr vs json_queryAnsible set_fact vs vars vs extra_varsAnsible ternary Filter GuideAnsible Jinja2 Templates Guide

Category: database-automation

Browse all Ansible tutorials · AnsiblePilot Home