Ansible Course
Inventory Files Explained
In this lesson
An inventory is the file — or dynamic data source — that tells Ansible which hosts to manage and how to connect to them. Every Ansible command needs an inventory: without one, Ansible has no targets to run against. Inventories can be as simple as a single IP address in a text file, or as sophisticated as a live query against a cloud provider's API that returns thousands of servers grouped by region, environment, and role. Mastering inventory is essential because it is the bridge between your automation code and your real infrastructure.
Static Inventory Formats
A static inventory is a file you write and maintain by hand. Ansible supports two formats: INI and YAML. Both express the same information — they are purely a matter of preference and team convention. INI is more compact; YAML is more explicit and integrates naturally with the rest of your Ansible project.
[groupname]
headers
INI inventory — inventory.ini
# Ungrouped hosts — reachable by Ansible but not in any named group
192.168.1.5
# A group called webservers
[webservers]
web01.example.com
web02.example.com ansible_port=2222 # override SSH port for this host only
# A group called databases
[databases]
db01.example.com ansible_user=dbadmin
db02.example.com
# A group of groups — 'production' contains both webservers and databases
[production:children]
webservers
databases
# Variables that apply to every host in the webservers group
[webservers:vars]
http_port=80
nginx_version=1.25
YAML inventory — inventory.yml
# The top-level key 'all' is mandatory — it is the implicit parent of every group
all:
children:
webservers:
hosts:
web01.example.com:
web02.example.com:
ansible_port: 2222 # override SSH port for this host only
vars:
http_port: 80
nginx_version: "1.25"
databases:
hosts:
db01.example.com:
db02.example.com:
vars:
db_port: 5432
production:
children:
webservers:
databases:
The Contacts App Analogy
An Ansible inventory is like a contacts app for your infrastructure. Each host is a contact — it has a name (hostname or IP), connection details (SSH user, port, key), and belongs to one or more groups (like "Work" or "Family"). When you run a playbook against the "webservers" group, it is the same as sending a message to everyone in a contact group — Ansible loops through every member automatically.
Groups, Children, and the all Group
Every inventory has two implicit groups that
always exist: all
— which contains every host in the inventory — and
ungrouped
— which contains hosts not assigned to any named group. Beyond these, you define your
own groups to organise hosts by role, environment, location, or any other dimension
that matters to your automation.
A group can contain hosts directly or contain
other groups as
children.
A host can belong to multiple groups simultaneously. When you run a playbook against
production, Ansible resolves the full member list — including all hosts in
webservers and databases — automatically.
Host Variables and Group Variables
Variables can be attached directly to hosts
or groups inside the inventory file — or, for larger projects, stored in dedicated
host_vars/
and
group_vars/
directories. This separation keeps your inventory clean and your variables easy to find.
Variable scope and where to define them
ansible_user, ansible_port, and
ansible_host. Applies to that host only.
[groupname:vars] section (INI) or under vars:
in a group (YAML). Applies to every host in that group. Useful for
group-wide settings like port numbers or package versions.
host_vars/
directory
A folder in your
project root. Create a file named after each host —
host_vars/web01.yml. Ansible loads it automatically. Best for
hosts with many variables.
group_vars/
directory
A folder in your
project root. Create a file named after each group —
group_vars/webservers.yml. Ansible loads it automatically for every
host in that group. The recommended approach for all but the simplest projects.
Recommended structure — group_vars/ directory
# Project directory layout — variables live outside the inventory file
myproject/
├── ansible.cfg
├── inventory.ini
├── site.yml
├── group_vars/
│ ├── all.yml # variables that apply to every host
│ ├── webservers.yml # variables for the webservers group only
│ └── databases.yml # variables for the databases group only
└── host_vars/
└── web01.yml # variables for web01 only (overrides group_vars)
Special Connection Variables
Ansible has a set of reserved variable names —
called
magic variables
— that control how it connects to each host. These can be set inline in the inventory or
in host_vars/ files to override the global defaults in
ansible.cfg.
ansible_host
The actual IP or hostname to connect to — useful when the inventory name is an alias that differs from the real address.
ansible_port
Overrides the SSH port for this host. Default is 22. Use when a server listens on a non-standard port.
ansible_user
The SSH user
to connect as. Overrides remote_user in ansible.cfg
for this specific host or group.
ansible_ssh_private_key_file
Path to the
SSH private key for this host. Overrides the global private_key_file
setting — useful when different hosts use different keys.
ansible_python_interpreter
Path to the
Python binary on the managed node. Set this when Python is at a non-standard
location, e.g. /usr/bin/python3.
ansible_connection
The connection
plugin to use. Default is ssh. Set to winrm for Windows
hosts or local to run tasks on the control node itself.
Verifying Your Inventory
Before running any playbook, use
ansible-inventory to inspect what Ansible sees in your inventory file.
This is the fastest way to catch typos, misconfigured groups, or missing variables
before they cause a failed run.
# List all hosts and groups in a human-readable tree format
ansible-inventory -i inventory.ini --graph
# Show the full inventory as JSON — reveals every variable resolved per host
ansible-inventory -i inventory.ini --list
# Show details for a single host — all variables that will apply to it
ansible-inventory -i inventory.ini --host web01.example.com
# Output of --graph @all: |--@ungrouped: | |--192.168.1.5 |--@production: | |--@webservers: | | |--web01.example.com | | |--web02.example.com | |--@databases: | | |--db01.example.com | | |--db02.example.com
What just happened?
Ansible printed the full group hierarchy as a tree.
You can immediately see which hosts belong to which groups, spot any host that ended up
in ungrouped by mistake, and confirm that parent/child group relationships
resolved correctly. Run this every time you edit your inventory.
Dynamic Inventory
A dynamic inventory is a script or plugin that generates the host list at runtime by querying an external source — a cloud provider API, a CMDB, or any other system that knows what servers exist. Instead of maintaining a hand-edited file, Ansible calls the script before each run and receives a fresh, up-to-date list of hosts and their metadata.
Dynamic inventory is the standard approach in cloud environments where servers are constantly being created, scaled, and terminated. You never want to maintain a static inventory for an auto-scaling group — by the time you update it, the server list has already changed. Ansible ships with built-in dynamic inventory plugins for AWS, GCP, Azure, VMware, OpenStack, and many others.
AWS EC2
amazon.aws.aws_ec2 — queries the EC2 API, groups hosts by region,
tag, VPC, and instance type automatically.
GCP
google.cloud.gcp_compute — queries the GCP Compute API and groups
by zone, label, and machine type.
Azure
azure.azcollection.azure_rm — queries Azure Resource Manager and
groups by resource group, location, and tag.
Official reference: Full documentation for all built-in dynamic inventory plugins — including setup, authentication, and filtering options for each cloud provider.
Inventory plugins ↗Never Define Sensitive Values Directly in the Inventory File
It is tempting to put passwords,
API keys, and database credentials directly in your inventory or
group_vars files for convenience. These files are committed to version
control — any secret stored in plain text is permanently exposed in your Git history,
even if you delete it later. Use Ansible Vault to encrypt sensitive variables, covered
in depth in Lesson 28.
Key Takeaways
all
(every host) and ungrouped (hosts not in any named group). These
exist whether you define them or not.
group_vars/ and host_vars/ directories
— keeping variables out of the inventory file keeps it readable and makes
variable management scalable as your project grows.
ansible_user and ansible_port
override global config — use them in inventory to apply host-specific or
group-specific connection settings without touching ansible.cfg.
ansible-inventory --graph
— run this after every edit to confirm groups, children, and host assignments
are exactly what you expect before running a playbook.
Teacher's Note
Get into the habit of running
ansible-inventory --graph after every inventory change — it takes two
seconds and will save you from running a playbook against the wrong set of hosts.
Practice Questions
1. What is the name of the implicit Ansible group that automatically contains every host in the inventory?
2. What command prints your inventory as a tree showing all groups and their member hosts?
3. Which magic variable overrides the SSH port for a specific host in the inventory?
Quiz
1. A playbook targets the
production group, which has webservers and
databases as children. What does Ansible do?
2. What is the recommended way to manage variables for a large Ansible project?
3. Your infrastructure runs on AWS with auto-scaling groups that add and remove servers constantly. What type of inventory should you use?
Up Next · Lesson 8
Ansible Ad-hoc Commands
Run single tasks against your inventory instantly — without writing a playbook. Ad-hoc commands are Ansible's fastest tool for one-off checks, quick fixes, and fleet-wide queries.