Ansible - Using YAML For Inventory
Refreshed June 2026: the YAML example now uses the canonical
all/childrenstructure, and I added two sections on checking and converting inventories withansible-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/varsstructure is the documented canonical form. The ungrouped hosts that the INI file listed at the top become entries underall.hosts. - Host range patterns like
www[001:006].example.comanddb-[99:101]-node.example.comwork 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