Why Ansible Variables Matter
Ansible variables let you write a single playbook that behaves differently for different hosts, environments, or runs, instead of hardcoding values like package versions, IP addresses, or feature flags directly into tasks. A variable can come from inventory files, role defaults, command-line flags, discovered facts, or registered task output, and Ansible merges all of these into one namespace for each host before executing a task.
Cricket analogy: Just as a franchise fields a different XI for a day game at the Wankhede versus a day-night game at Eden Gardens without rewriting the team's playbook, Ansible variables let one playbook adapt its behavior per host without duplicating tasks.
Where Variables Can Live
Variables can be declared in inventory files (as host or group vars), in group_vars/ and host_vars/ directories, inside a play with the vars: keyword, in role defaults/main.yml and vars/main.yml, loaded dynamically with vars_files or include_vars, captured at runtime with set_fact or register, or passed on the command line with -e. Each location has a different intended purpose: role defaults are meant to be overridden, while extra vars are meant to override everything else.
Cricket analogy: A team's base strategy sits in the coaching manual (role defaults), but the captain can override field placements mid-over from the crease (-e extra vars), showing that some sources are meant to be easily overruled.
The Precedence Order in Practice
Ansible resolves conflicting values using roughly twenty-two precedence levels, documented in order from lowest to highest. Role defaults sit at the bottom, followed by inventory vars, inventory group_vars and host_vars files, play vars, block vars, task vars, and role vars/main.yml, with facts and registered variables sitting in the middle, and command-line extra vars (-e) always winning regardless of where else the variable is defined. Understanding this order is essential when a value 'doesn't seem to apply' during a run.
Cricket analogy: Match regulations rank the ICC playing conditions above a home ground's local rule, so if Eden Gardens has a quirky boundary rule that conflicts with ICC law, ICC law wins, just as extra vars always outrank every other Ansible source.
Common Precedence Pitfalls
The most frequent surprise is that role vars/main.yml has higher precedence than role defaults/main.yml, so a value placed in vars/main.yml cannot be overridden by group_vars the way a defaults/main.yml value can — this is why role authors are told to put tunable knobs in defaults and internal constants in vars. Another common trap is assuming host_vars always beats group_vars: it does, but only when both target the exact same host, and a more specific child group does not automatically beat a less specific group unless inventory group nesting is set up correctly.
Cricket analogy: A bowler assumes a yorker will always beat a batter, but against Jos Buttler's reach and reflexes it doesn't automatically work, just as assuming host_vars always 'wins' without checking group nesting can surprise you.
# roles/webserver/defaults/main.yml (lowest precedence, meant to be overridden)
http_port: 8080
max_connections: 100
# roles/webserver/vars.yml (higher precedence, treat as role internals)
app_install_dir: /opt/webserver
# inventory/group_vars/production.yml
http_port: 443
max_connections: 500
# inventory/host_vars/web01.yml
http_port: 8443
# Run with an extra var, which always wins over every file above:
# ansible-playbook site.yml -e "http_port=9090"
- name: Show effective value
hosts: web01
tasks:
- name: Print resolved http_port
ansible.builtin.debug:
var: http_portUse ansible-inventory --host <hostname> --yaml or ansible <hostname> -m ansible.builtin.debug -a "var=hostvars[inventory_hostname]" to inspect exactly which variables Ansible resolved for a host before you run a full playbook.
Command-line extra vars (-e) silently override everything, including values you carefully set in host_vars for a specific machine. If a variable 'won't change' no matter what you edit in inventory files, check whether it is being passed with -e in your CI pipeline or wrapper script first.
- Ansible merges variables from over twenty possible sources into one namespace per host before running tasks.
- Role defaults/main.yml is the lowest-precedence source and is meant to be freely overridden by inventory variables.
- Role vars/main.yml has much higher precedence than defaults and is not meant to be casually overridden.
- host_vars beats group_vars only when both target the same host; group nesting affects which group_vars file wins.
- Command-line extra vars (-e) always win over every other source, regardless of specificity.
- Use ansible-inventory --host or the debug module with hostvars to inspect resolved values before assuming precedence.
- Facts and registered variables sit in the middle of the precedence chain, above most static inventory sources.
Practice what you learned
1. Which variable source has the highest precedence in Ansible and will override all others?
2. Where should a role author place values that are meant to be freely overridden by users of the role?
3. If both group_vars/webservers.yml and host_vars/web01.yml define the same variable for host web01, which value is used?
4. Why might a value in a role's vars/main.yml fail to be overridden by group_vars, even though group_vars usually overrides role defaults?
5. What is the fastest way to confirm which value Ansible actually resolved for a variable on a given host?
Was this page helpful?
You May Also Like
Group and Host Variables
How Ansible's group_vars and host_vars directories organize variables by inventory group and individual host, and how group nesting affects precedence.
Jinja2 Templating in Ansible
How Ansible uses the Jinja2 templating engine for variable substitution, filters, conditionals, and generating configuration files dynamically.
Facts and Gathering Facts
How Ansible discovers system information automatically with the setup module, how to extend it with custom facts, and how fact caching speeds up large runs.
Vault and Secrets Management
How Ansible Vault encrypts sensitive data at rest, how vault IDs support multiple passwords, and how to integrate vault into automated pipelines safely.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics
DevOpsCI/CD Tools & Pipelines Study Notes
YAML · 37 topics