unit 3 · Inventory

group_vars & host_vars

Config files that find their hosts by name

essential · 6 min · linux + windows

you may want to read 8 · Inventory: INI and YAML first — but nothing is locked

tl;dr

  • group_vars/ and host_vars/ sit next to your inventory and auto-load by group and host name.
  • Environment config lives here — per group in group_vars, pinned to one machine in host_vars.
  • group_vars/all.yml hits every host in the inventory. Keep it minimal.

why it matters Every real repo carries these directories. If you don’t know the files load themselves by name, you’ll hunt for an import that doesn’t exist — and put environment config in all the wrong places.

Lesson 8 gave you groups. This lesson gives those groups configuration — and the mechanism is two directories, group_vars and host_vars , that live next to your inventory file. The entire trick is in the filenames:

inventory/
├── hosts.yml           # your lesson-8 inventory: web, db, all the groups
├── group_vars/
│   ├── all.yml         # every host in the inventory — keep it minimal
│   └── web.yml         # every host in the web group
└── host_vars/
    └── web01.yml       # exactly one machine: web01
Nothing references these files anywhere. The names do all the work.

There is no import line, no path setting, no reference from the inventory. Ansible auto-loads each file by matching its name against your group and host names: group_vars/web.yml applies to every host in web, host_vars/web01.yml applies to the single host web01, and group_vars/all.yml applies to everything, because every host belongs to the built-in all group. Inside, a vars file is nothing but YAML keys and values:

# loaded automatically for every host in the web group
app_env: staging
http_port: 8080
motd_message: 'managed by ansible - do not hand-edit'
group_vars/web.yml — no boilerplate, just values

Where environment config lives

The rule of thumb is blunt: environment config lives here. Ports, service endpoints, tuning values, anything that varies between staging and production — that belongs in group_vars, not hardcoded into a playbook and not scattered across the inventory file itself. Later, when roles arrive in Unit 6, you’ll see the full division of labour: user-tunable defaults in the role, environment values in group_vars.

Two habits separate tidy repos from haunted ones:

  • Keep group_vars/all.yml minimal. A value in all.yml touches every host in the inventory, so it earns its place only by being genuinely universal. Environment-specific values belong in the environment’s own inventory directory — more on that below.
  • Use host_vars/ sparingly, for values true of one machine only. If you’re writing the same key into three host files, those hosts are telling you they want to be a group.

Your inventory now says both who your hosts are and what is true about them — and everything loads by naming convention, with zero wiring. Real repos push this one step further: a separate inventory directory per environment (inventories/production/, inventories/staging/), each with its own group_vars and host_vars, so staging values can never bleed into prod. That structure — plus the patterns that pick which hosts a run actually touches — is lesson 10.

self-check — recall, not a test

  1. 1 You create group_vars/web.yml. What do you have to add elsewhere so Ansible loads it?

  2. 2 An NTP server address differs between staging and production. Where does it belong?

  3. 3 Your group_vars value isn’t the one showing up at runtime. What do you know so far, and where’s the full answer?

lab (optional — never required)

Rebuild this lesson’s tree next to your lesson-8 inventory, then prove the values load with an ad-hoc ansible.builtin.debug call against the web group.

needs: The control node and inventory from lessons 5–8.

PLAY RECAP ************************** 09-group-vars-and-host-vars : ok=1 next=10-patterns-and-limit read=7m