Ansible - Using YAML For Inventory

3 minute read

Refreshed June 2026: the YAML example now uses the canonical all / children structure, and I added two sections on checking and converting inventories with ansible-inventory. All command output below is from ansible-core 2.19.

Background

Most of us started out writing Ansible inventory in the INI format. It works, but once you are maintaining an INI inventory at any real scale it gets hard to read and easy to break. YAML is the other built-in option, and for anything beyond a handful of hosts I find it cleaner to manage and easier to diff in review. This post shows the same inventory both ways and then how to verify the result.

The INI Inventory

Here is a small inventory in INI format with a mix of ungrouped hosts, two groups, and some group variables.

green.example.com ansible_host=10.0.101.100
blue.example.com
192.168.100.1
192.168.100.10

[webservers]
alpha.example.org
beta.example.org ansible_host=192.168.200.122
192.168.1.100
192.168.1.110
www[001:006].example.com

[webservers:vars]
nginx_http_port=80
nginx_https_port=443

[dbservers]
db01.intranet.mydomain.net
db02.intranet.mydomain.net
10.25.1.56
10.25.1.57
db-[99:101]-node.example.com

The first four hosts are ungrouped, then there are webservers and dbservers groups, with two variables scoped to webservers.

The YAML Inventory

The same inventory in YAML uses a top-level all group. Hosts that belong to no group sit under all.hosts, and every other group is nested under all.children. Group variables go under a vars key on the group.

---
all:
  hosts:
    green.example.com:
      ansible_host: 10.0.101.100
    blue.example.com:
    192.168.100.1:
    192.168.100.10:
  children:
    webservers:
      hosts:
        alpha.example.org:
        beta.example.org:
          ansible_host: 192.168.200.122
        192.168.1.100:
        192.168.1.110:
        www[001:006].example.com:
      vars:
        nginx_http_port: 80
        nginx_https_port: 443
    dbservers:
      hosts:
        db01.intranet.mydomain.net:
        db02.intranet.mydomain.net:
        10.25.1.56:
        10.25.1.57:
        db-[99:101]-node.example.com:

A few things worth pointing out:

  • The all / hosts / children / vars structure is the documented canonical form. The ungrouped hosts that the INI file listed at the top become entries under all.hosts.
  • Host range patterns like www[001:006].example.com and db-[99:101]-node.example.com work the same in YAML as they do in INI.
  • A host with no per-host variables is just a key with an empty value, like blue.example.com:.

Verify It With ansible-inventory

The reason I trust a conversion like this is that I do not have to eyeball it. ansible-inventory --graph renders whatever Ansible actually parsed, so you can confirm the structure is what you intended.

ansible-inventory -i inventory.yml --graph
@all:
  |--@ungrouped:
  |  |--green.example.com
  |  |--blue.example.com
  |  |--192.168.100.1
  |  |--192.168.100.10
  |--@webservers:
  |  |--alpha.example.org
  |  |--beta.example.org
  |  |--192.168.1.100
  |  |--192.168.1.110
  |  |--www001.example.com
  |  |--www002.example.com
  |  |--www003.example.com
  |  |--www004.example.com
  |  |--www005.example.com
  |  |--www006.example.com
  |--@dbservers:
  |  |--db01.intranet.mydomain.net
  |  |--db02.intranet.mydomain.net
  |  |--10.25.1.56
  |  |--10.25.1.57
  |  |--db-99-node.example.com
  |  |--db-100-node.example.com
  |  |--db-101-node.example.com

Run the same command against the INI file and you get an identical graph, which is the proof that the two inventories are equivalent. Note that the ranges are expanded and the ungrouped hosts land in the built-in ungrouped group.

Add --vars to see the variables that resolve onto each host:

ansible-inventory -i inventory.yml --graph --vars webservers
@webservers:
  |--alpha.example.org
  |  |--{nginx_http_port = 80}
  |  |--{nginx_https_port = 443}
  |--beta.example.org
  |  |--{ansible_host = 192.168.200.122}
  |  |--{nginx_http_port = 80}
  |  |--{nginx_https_port = 443}
  ...

Converting An Existing INI Inventory

If you already have an INI inventory and want a head start on the YAML version, ansible-inventory will dump it for you:

ansible-inventory -i inventory.ini --list --yaml
all:
  children:
    dbservers:
      hosts:
        db01.intranet.mydomain.net: {}
        ...
    ungrouped:
      hosts:
        green.example.com:
          ansible_host: 10.0.101.100
        ...
    webservers:
      hosts:
        beta.example.org:
          ansible_host: 192.168.200.122
          nginx_http_port: 80
          nginx_https_port: 443
        ...

One caveat: this output expands host ranges into individual hosts and copies group variables down onto every host. It is a faithful dump of what Ansible resolved, not a hand-maintainable file. Treat it as a starting point to clean up, lift the shared variables back into a group vars block, and re-collapse any ranges you want to keep as patterns.

Conclusion

YAML inventory has not changed much since I first wrote this, and that is the point. It is still the format I reach for when an inventory grows past trivial, and ansible-inventory --graph is the habit that keeps me honest about what I actually defined.

Enjoy!

Comments