What is an Ansible inventory, and what do the built-in `all` and `ungrouped` groups contain?
answer
- Ansible cannot discover hosts by itself
- INI or YAML, or a dynamic source
- two groups you never declare
- every host belongs to one of them
- the other holds hosts with no group
basics
~20 sAn Ansible inventory is the list of managed hosts and the groups holding them, written as static INI or YAML files or produced by a dynamic plugin. Every host is automatically in the group all; a host in no other group is also in ungrouped.
solid answer
~40 sAnsible is agentless, so it has no way to discover machines — the inventory is the only thing that tells it which hosts exist. It can be a static INI or YAML file, a directory of such files that Ansible merges, or a dynamic plugin that queries a cloud API. The inventory names hosts, arranges them into groups and groups-of-groups via `children`, and can attach variables to a host or a group. Two groups always exist without being declared: `all`, which holds every host in the inventory, and `ungrouped`, which holds hosts that belong to no group other than `all`. Plays target those names — `hosts: webservers`, `hosts: all` — so the inventory is what decides blast radius. Before running anything against an unfamiliar inventory I check it with `ansible-inventory -i <source> --graph`.
code
ini · 13 lines[webservers]
web01 ansible_host=10.0.1.11
web[02:05].example.com
[dbservers]
db01 ansible_host=10.0.2.21
[prod:children]
webservers
dbservers
[prod:vars]
ntp_server=time.internalgo deeper
Be able to write a small inventory in both INI and YAML, put hosts into a group, and say that all covers every host while ungrouped covers hosts with no group.
Explain group nesting with children, host ranges, where variables can be attached, and how multiple inventory sources or a directory get merged into one host set.
Show that you treat the inventory as the blast-radius control: it lives in the repository, is reviewed, and is verified with ansible-inventory --graph or --list-hosts before a production run.
Own the estate-wide question of what an inventory is allowed to contain — whether one inventory may ever address more than one environment, and who reviews changes to it.
## Why an inventory exists Ansible installs no agent. It connects outward, usually over SSH, runs a module and disconnects, which means it cannot discover infrastructure on its own. The inventory is the single source of "which machines may this run touch", and that is why interviewers treat it as a blast-radius question rather than a file-format question. An inventory source can be a static file, a directory of files that Ansible parses and merges, a dynamic inventory plugin configured by a YAML file, or an executable script that prints JSON. You point at it with `-i` (repeatable), or set `inventory` in `ansible.cfg`. The historical default is `/etc/ansible/hosts`, which real projects almost never use because inventory belongs in the repository next to the playbooks. ## The INI format ```ini [webservers] web01 ansible_host=10.0.1.11 web[02:05].example.com [dbservers] db01 ansible_host=10.0.2.21 [prod:children] webservers dbservers [prod:vars] ntp_server=time.internal ``` Three section shapes matter: a bare `[group]` lists hosts, `[group:vars]` attaches variables to the whole group, and `[group:children]` makes a group of groups. `web[02:05].example.com` is a host range, expanding to four hosts. Inline `key=value` after a host name sets host variables. ## The YAML format ```yaml all: children: webservers: hosts: web01: ansible_host: 10.0.1.11 dbservers: hosts: db01: {} prod: children: webservers: {} dbservers: {} vars: ntp_server: time.internal ``` YAML expresses the same model with real nesting and typed values, and it is what most teams standardise on. Note the shape: a group has `hosts:` and/or `children:` and optionally `vars:`. ## Groups, nesting and membership A host may be in many groups, and group membership is transitive upward: a host in `webservers` is also in `prod` when `prod` lists `webservers` as a child. That is what makes `hosts: prod` work without repeating hosts. Groups are just labels — they carry no ordering or ownership beyond variable resolution. ## The implicit groups `all` is created for you and contains every host the inventory produced, including hosts that came from a dynamic plugin. `ungrouped` contains hosts that ended up in no group other than `all` — usually hosts listed at the top of an INI file before any `[section]` header. Seeing hosts in `ungrouped` when you expected them in `webservers` is a fast signal that a section header is missing or misspelled. One special case surprises people: Ansible provides an *implicit localhost* with `ansible_connection=local`, so `hosts: localhost` works even when localhost is nowhere in the inventory. That implicit entry is not matched by `all` or `*`; you must name it. ## Verifying before you run ```bash ansible-inventory -i inventories/prod --graph ansible-inventory -i inventories/prod --list --yaml ansible-playbook -i inventories/prod site.yml --list-hosts ``` `--graph` prints the group tree with hosts under it, `--list` dumps hosts with their resolved variables, and `--list-hosts` on a playbook shows exactly which hosts a play would target. Running these first is the cheap habit that prevents "I thought that group was empty". ## What goes wrong in practice Hosts silently landing in `ungrouped`; a group name typo so `hosts: webserver` matches nothing; assuming `all` includes the control node; and treating the inventory as documentation rather than as the executable definition of blast radius. In a real repository the inventory is reviewed as carefully as the playbooks, because adding one line to the wrong group is enough to reconfigure a production database.
- If a host appears in two different files inside one inventory directory, what does Ansible do?It merges them. Pointing `-i` at a directory makes Ansible parse every file in it and combine the results, so the same host can be declared in one file and added to another group in a second file. That is how teams split a static core inventory from a dynamic cloud source while still targeting one merged set of groups.
- Why do most teams avoid the default `/etc/ansible/hosts` inventory?Because it lives outside the repository, so it is not reviewed, not versioned, and differs between the laptop and the CI runner. Inventory decides which machines a run touches, so it belongs beside the playbooks under `-i inventories/<env>` or an explicit `inventory` setting in a project-local `ansible.cfg`.
- How do you confirm which hosts a play will actually target before running it?`ansible-inventory -i <source> --graph` shows the group tree and its hosts, and `ansible-playbook -i <source> site.yml --list-hosts` prints the hosts each play resolves to without connecting to anything. Both are read-only and take a second, which makes them the standard pre-flight check.
saying these in an interview costs you the question
- Thinking Ansible auto-discovers hosts on the network
- Believing you must declare the all group yourself
- Saying ungrouped means hosts that failed to connect
- Assuming a host in a child group is not in the parent
- Claiming inventory must be a single INI file