group_vars and host_vars: Where Settings Live

Scenario: Staging values leaked into production. The cause was a variable in group_vars/all.yml that someone assumed only applied to staging.

New words, in plain English

Hard-coding values inside tasks makes automation unreusable. Variables move those values out into files organised by who they apply to, which is the whole design.

The conventional layering is worth learning as a rule of thumb and then internalising:

Ansible also supports a directory instead of a file: group_vars/dbservers/ containing vars.yml and vault.yml is loaded as one merged set. That pattern matters enormously later, because it lets you keep secrets encrypted in vault.yml while ordinary settings stay readable in vars.yml.

Analogy: Company policy applies to everyone. A department can set its own stricter rule. An individual can have a documented exception. And the CEO can override anything in an emergency - which is fine occasionally, and a disaster as a routine.

A worked example

# group_vars/all.yml - true for the whole estate
ntp_server: time.internal
app_env: production

# group_vars/webservers.yml - true for the web tier
app_port: 8081
worker_count: 4

# host_vars/lb01.yml - a genuine, documented exception
# lb01 fronts a legacy partner integration on a fixed port.
app_port: 8088

# group_vars/dbservers/  (a DIRECTORY, loaded as one set)
#   vars.yml   -> db_user: checkout_app
#   vault.yml  -> encrypted secrets

Ansible looks for group_vars/ and host_vars/ in two places: next to the playbook, and next to the inventory. Inventory-adjacent is the better default for anything that describes the estate, because tools like ansible-inventory --host web01 can then resolve it too. Playbook-adjacent is fine for values that only make sense to that playbook.

The practical debugging move when a value is wrong: do not read the files hunting for it. Ask Ansible. ansible-inventory --host web01 prints every inventory-sourced variable for that host, and a debug task prints the fully-resolved value at the exact point the play would use it.

Tip: A variable that needed a comment explaining why it is in host_vars is usually correct. A variable in group_vars/all.yml that needed a comment explaining who it does NOT apply to is usually in the wrong place.
Goal: Put this to work in the ansible-variable-precedence lab. Open /labs/ansible, pick ansible-variable-precedence, and fix the real broken project - Ansible really does SSH into four managed hosts and converge them.