Variables and Precedence
Relevant source files
The following files were used as context for generating this wiki page:
Ansible allows variables to be defined in many different places, including the command line, playbooks, inventory files, included files, and roles. This flexibility requires a clear understanding of the order in which these variables are applied, known as variable precedence. When a variable is defined in multiple locations, the definition with the highest precedence is the one that Ansible will use for the task execution.
This document outlines the mechanisms governing variable precedence, the configuration options that influence variable merging, and the various sources from which variables are loaded. The primary order of precedence is determined by an integration test designed specifically to validate this behavior.
Sources: test/integration/targets/var_precedence/ansible-var-precedence-check.py
Core Configuration
Ansible's variable handling can be modified by global settings in ansible.cfg. These settings control how variables, particularly dictionaries, are merged and the precedence of group variables.
Hash Merge Behavior (DEFAULT_HASH_BEHAVIOUR)
This setting controls how Ansible handles dictionary variables (hashes) that are defined in multiple places.
| Behavior | Description |
|---|---|
replace (default) | The variable definition with the highest precedence completely overwrites any previous definitions. |
merge | Dictionary variables are recursively merged. Keys from a higher-precedence definition are added to or overwrite keys in a lower-precedence dictionary. |
Warning: The documentation strongly advises against changing this setting to merge for new projects, as it can make content non-portable and debugging difficult. The combine filter is the recommended alternative for merging dictionaries.
Sources: lib/ansible/config/base.yml:640-671
Group Variable Precedence (VARIABLE_PRECEDENCE)
This setting allows for changing the merge order of group variables. It does not affect the overall variable precedence stack, only the order in which variables from different inventory groups are merged.
The default precedence order for group variables is:
all_inventorygroups_inventoryall_plugins_inventoryall_plugins_playgroups_plugins_inventorygroups_plugins_play
Sources: lib/ansible/config/base.yml:1181-1189
Variable Precedence Order
The order of precedence determines which variable value is used when the same variable is defined in multiple locations. The following diagram and list describe the order from highest precedence (wins) to lowest precedence. This order is validated by the ansible-var-precedence-check.py integration test.
This diagram illustrates the flow of variable overriding, from the lowest precedence (Role Defaults) to the highest (Extra Vars).
The definitive order of precedence, from highest to lowest, is as follows:
- Extra Vars (
-e): Variables passed on the command line. - Include Params: Variables passed to an
include_tasksstatement. - Set Fact / Registered Vars: Variables created dynamically by tasks using
set_factorregister. - Include Vars: Variables loaded dynamically using the
include_varsmodule. - Task Vars: Variables defined directly on a task (
vars:keyword). - Block Vars: Variables defined on a block (
vars:keyword). - Role Vars: Variables from
vars/main.ymlwithin a role. - Play Vars Files: Variables loaded from files specified in the
vars_filessection of a play. - Play Vars: Variables defined in the
vars:section of a play. - Playbook
host_vars: Variables in files located in ahost_vars/directory relative to the playbook. - Inventory
host_vars: Variables in files located in ahost_vars/directory relative to the inventory file. - Inventory Host Vars: Variables defined on the host's line in the inventory file (e.g.,
myhost http_port=80). - Playbook
group_vars(child group): Variables for a specific group ingroup_vars/relative to the playbook. - Playbook
group_vars(parent group): Variables for a parent group ingroup_vars/relative to the playbook. - Inventory
group_vars(parent group): Variables for a parent group ingroup_vars/relative to the inventory. - Playbook
group_vars(all): Variables for all hosts ingroup_vars/allrelative to the playbook. - Inventory
group_vars(all): Variables for all hosts ingroup_vars/allrelative to the inventory. - Inventory Group Vars (child group): Variables defined for a child group in the inventory file.
- Inventory Group Vars (parent group): Variables defined for a parent group in the inventory file.
- Inventory Group Vars (all): Variables defined for the
allgroup in the inventory file. - Role Defaults: Variables from
defaults/main.ymlwithin a role (and its dependencies).
Sources: test/integration/targets/var_precedence/ansible-var-precedence-check.py:410-441, test/integration/targets/var_precedence/ansible-var-precedence-check.py:452-485
Variable Sources
Role Variables
Roles are a primary way of organizing content, and they define variables in two main locations, which have different precedence levels.
defaults/main.yml: Contains default variables for a role. These variables have the lowest precedence of almost any source and are intended to be easily overridden.vars/main.yml: Contains variables for a role that have a higher precedence than defaults. These variables are meant for internal role use and are not as easily overridden.
The precedence test script confirms that role_var (from vars/main.yml) has higher precedence than role_default (from defaults/main.yml).
Sources: lib/ansible/galaxy/data/default/role/README.md:11-14, test/integration/targets/var_precedence/ansible-var-precedence-check.py:302-307, test/integration/targets/var_precedence/ansible-var-precedence-check.py:321-325
Inventory Variables
Variables can be defined directly within or adjacent to the inventory file.
- INI Format: Variables can be placed directly on a host's line or in
[group:vars]sections. - Dynamic Inventory: Scripts can generate JSON output that defines host and group variables.
- Directory-Based Vars: Ansible automatically loads variables from files in
host_vars/andgroup_vars/directories located next to either the inventory file or the playbook file. The precedence test script shows that playbook-adjacentgroup_varsandhost_varsoverride inventory-adjacent ones.
Sources: test/integration/targets/var_precedence/ansible-var-precedence-check.py:193-255
Dynamic Variable Loading (include_vars)
The include_vars module allows for loading variables from a file or directory dynamically during a task's execution. This is a powerful way to load context-specific data.
Key parameters for include_vars:
| Parameter | Description |
|---|---|
file | Path to a single YAML or JSON file to load. |
dir | Path to a directory from which to load all valid variable files. |
name | The name of a top-level variable to assign the loaded vars to. If omitted, vars are loaded at the top level. |
hash_behaviour | Can be set to merge to merge the loaded variables with existing hash variables, overriding the global DEFAULT_HASH_BEHAVIOUR. |
extensions | A list of file extensions to consider when loading from a directory. Defaults to ['json', 'yaml', 'yml']. |
The include_vars module has a high precedence, but it is lower than variables created by set_fact or passed as include_params.
Sources: lib/ansible/modules/include_vars.py:11-82, test/integration/targets/var_precedence/ansible-var-precedence-check.py:296-301
Conclusion
Understanding Ansible's variable precedence is crucial for writing predictable and maintainable automation. The order is strictly defined and tested, with command-line extra-vars having the highest precedence and role defaults having the lowest. Key configuration settings like DEFAULT_HASH_BEHAVIOUR can alter how dictionary variables are merged, but the fundamental precedence stack remains consistent. By leveraging this hierarchy, developers can design robust roles and playbooks where variable values can be set at the appropriate level, from universal defaults to specific, task-level overrides.