Ansible variables let one playbook deploy different ports, packages, credentials, hosts, and environments without duplicating tasks. Define values in playbooks, vars_files, inventory group_vars and host_vars, or create them during a run with set_fact and register. Reference them with Jinja expressions such as {{ app_port }}. When definitions conflict, Ansible applies variable precedence; extra variables passed with --extra-vars (or -e) are the highest-priority override.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
What an Ansible variable is
A variable is a named value that Ansible evaluates while it parses a play, selects hosts, runs tasks, or renders a template. The value can be a string, number, Boolean, list, or mapping. Keeping data separate from task logic means the same task sequence can serve development, staging, and production with different inventory or runtime values.
As an Amazon Associate I earn from qualifying purchases.
Recommended Free Tools
Use a variable in a task or template by placing its name inside a Jinja expression:
- name: Install the selected package
ansible.builtin.package:
name: '{{ app_package }}'
state: present
- name: Listen on the configured port
ansible.builtin.template:
src: app.conf.j2
dest: /etc/myapp/app.conf
In app.conf.j2, the corresponding expression could be port {{ app_port }}. Keep the data definition in one of the variable sources below, and keep the task focused on the action.
#1 Best Overall
Choose the right place to define a value
Ansible reads variables from several locations. The best location depends on who owns the value, how widely it is shared, and whether it must change during execution.
| Source | Scope | Use it for |
|---|---|---|
Play vars |
The play where it is declared | Small, play-specific settings that should travel with the playbook |
vars_files |
The play that loads the file | Configuration kept in a separate YAML file, such as environment settings |
Inventory group_vars |
Every host in a group | Shared defaults for a role, environment, or machine class |
Inventory host_vars |
One inventory host | Per-host exceptions, addresses, ports, or hardware-specific values |
set_fact |
A host during the run | A value calculated or discovered by an earlier task |
register |
A host during the run | The result returned by a task or module |
Extra variables (-e or --extra-vars) |
The command invocation | An intentional run-time override, such as a one-off release version |
As a rule, put stable shared defaults in group_vars, host exceptions in host_vars, and temporary calculated values in set_fact or register. Use extra variables when the person launching the run must explicitly force a value.
Define variables directly in a play
A play can contain a vars mapping. This is convenient when the values are tightly coupled to that play and are unlikely to be reused elsewhere.
- name: Configure the game service
hosts: game_servers
vars:
app_package: game-server
app_port: 27015
log_level: info
feature_flags:
telemetry: false
replays: true
tasks:
- name: Install the service package
ansible.builtin.package:
name: '{{ app_package }}'
state: present
- name: Render service configuration
ansible.builtin.template:
src: game-server.conf.j2
dest: /etc/game-server.conf
Scalar values such as info and numbers can be used directly. A mapping such as feature_flags groups related settings and is referenced with a dotted expression, for example {{ feature_flags.replays }}. Keep variable names descriptive and consistent; a misspelled name is a different variable, not an alias.
If the same variable name is written more than once in a play’s vars section, the later definition wins according to the official ansible-core 2.15 documentation. Avoid relying on that behavior: keep one authoritative definition so a future edit cannot silently change the result.
Load values from a vars file
Move configuration out of the playbook when it is larger, environment-specific, or maintained by a different person. Declare the file with vars_files:
Free tools Windows power users keep installed
One-click scans. No signup required.
- name: Deploy the service
hosts: game_servers
vars_files:
- vars/common.yml
- vars/staging.yml
tasks:
- name: Render configuration
ansible.builtin.template:
src: game-server.conf.j2
dest: /etc/game-server.conf
A file loaded this way is ordinary YAML:
app_package: game-server
app_port: 27015
log_level: info
Keep the file path under version control with the playbook when it is non-secret configuration. Sensitive values should be handled with the secret-management approach used by your organization rather than copied into command history or committed as plain text. The important variable behavior is that a value loaded from a file still participates in Ansible’s precedence rules; another source with higher precedence can replace it.
Use group_vars and host_vars in inventory
Inventory variables are the natural choice when the same playbook targets several environments or machine groups. A typical layout is:
Rank #2
inventory/
hosts.yml
group_vars/
all.yml
game_servers.yml
host_vars/
server-a.yml
server-b.yml
group_vars/all.yml can hold a value shared by every inventory host. group_vars/game_servers.yml can hold defaults for the game_servers group:
app_package: game-server
app_port: 27015
log_level: info
Use host_vars/server-a.yml for a single host’s exception:
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →app_port: 27016
The official precedence material places host_vars above group_vars, so the host-specific port takes precedence for server-a while other members keep the group value. This arrangement avoids copying an entire group configuration merely to change one host.
If multiple groups define the same variable, the latest page for using variables states that the last group loaded wins. Because load order can make a conflict difficult to see, give related groups distinct variable names or define a deliberate host-level exception instead of depending on overlapping group definitions.
Create values while a play is running
Calculate a value with set_fact
set_fact creates a host variable from values already available to the play. It is useful when a path, label, or decision depends on facts gathered earlier:
- name: Select the configuration directory
ansible.builtin.set_fact:
config_dir: '/etc/{{ app_package }}'
- name: Create the selected directory
ansible.builtin.file:
path: '{{ config_dir }}'
state: directory
mode: '0755'
The value is available to later tasks for that host in the current run. The precedence model means a stale fact can hide a corrected value from group_vars or another file-based source. If a variable appears unchanged after you edit inventory, inspect tasks that set it and any fact-caching configuration before changing the inventory again.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesCapture a task result with register
register stores the result returned by a task so a later task can inspect it:
- name: Check whether the service is listening
ansible.builtin.command: ss -lnt
register: listening_ports
changed_when: false
- name: Show the command output
ansible.builtin.debug:
var: listening_ports.stdout
A registered value is a result object, not automatically the text you expected. Modules commonly expose fields such as standard output, return code, and change status. Read the field you need and guard follow-up logic against a failed command or an absent field. The exact precedence position of registered variables, like that of set_fact, can differ between Ansible documentation versions, so consult the precedence page for the ansible-core release you run.
Rank #3
Override a value for one run with extra vars
Pass an extra variable on the command line when a deployment must use a deliberate one-time value:
ansible-playbook -i inventory/hosts.yml deploy.yml -e 'app_port=28015'
The official precedence guidance puts extra variables at the top of the stack. They are therefore the appropriate mechanism when you need to override a value from play variables, inventory, or a vars file without editing those sources. Treat this power carefully: an extra variable can mask a correction in your repository and command-line values may be visible in shell history or process listings.
For several values, pass a YAML or JSON mapping in the format supported by your Ansible installation, or use repeated key-value arguments. Keep the invocation documented in your deployment system so another operator can reproduce the same input.
Reference variables in tasks, templates, and conditions
Module arguments
Quote a Jinja expression when it is embedded in a YAML string:
- name: Set the service name
ansible.builtin.service:
name: '{{ app_package }}'
state: started
When the entire value is a number or Boolean, preserve its type when the module expects one. A value written as a quoted string may be interpreted differently from an unquoted YAML number or Boolean, so match the module’s documented parameter type.
Templates
Template files use the same Jinja expression syntax:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
[server]
port={{ app_port }}
log_level={{ log_level }}
replays={{ feature_flags.replays }}
Keep templates declarative. Put calculations and selection logic in variables or tasks when that makes the resulting configuration easier to test.
Conditions
Variables can control whether a task runs:
- name: Enable replay storage
ansible.builtin.service:
name: replay-storage
state: started
when: feature_flags.replays
Do not wrap a bare variable in an extra Jinja expression inside when; the condition is already evaluated as an expression. If a value may be absent, establish it in the appropriate variable source or use a documented defaulting pattern before the conditional task.
Rank #4
Understand variable precedence without guessing
Ansible can load the same variable name from several places. It does not merge those definitions indiscriminately; it selects one according to a precedence hierarchy. The hierarchy is version-dependent, so use the precedence page matching your ansible-core release whenever the exact order matters.
- The official ansible-core 2.15 documentation describes a 13-step order. Its lower-to-higher list includes role defaults, inventory and playbook group variables, host variables, facts and cached
set_factvalues, play variables, and prompted play variables, along with command-line values. - Ansible 7 documentation describes a longer 22-step order that additionally distinguishes
vars_files, role variables, block variables, task variables,include_vars,set_fact, registered variables, and role or include parameters. - Both documentation sets put extra variables supplied with
-eat the top. - Host-specific variables rank above group variables in the documented ordering.
- The exact placement of
set_fact,register, and include parameters differs between versions and between third-party explanations. Do not copy a numeric rank without checking the release you operate.
Think of precedence as an override decision, not as a reason to define the same key everywhere. Give a variable one clear owner, then use a higher-precedence source only for an intentional exception.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →A worked example with environment defaults and a host exception
The following arrangement keeps shared settings in inventory, allows one server to use a different port, and permits a release operator to override the package version for a single run.
inventory/
hosts.yml
group_vars/
game_servers.yml
host_vars/
server-a.yml
playbooks/
deploy.yml
group_vars/game_servers.yml:
app_package: game-server
app_version: '1.8'
app_port: 27015
host_vars/server-a.yml:
app_port: 27016
playbooks/deploy.yml:
- name: Deploy the game service
hosts: game_servers
tasks:
- name: Install the requested package version
ansible.builtin.package:
name: '{{ app_package }}={{ app_version }}'
state: present
- name: Render the service configuration
ansible.builtin.template:
src: game-server.conf.j2
dest: /etc/game-server.conf
- name: Record the effective configuration
ansible.builtin.debug:
msg:
- 'package={{ app_package }}'
- 'version={{ app_version }}'
- 'port={{ app_port }}'
With no command-line override, server-a receives port 27016 and other group members receive 27015. To test a different package version once, run:
ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml -e 'app_version=1.9'
The debug task is a useful, temporary way to confirm the effective values on each host before removing diagnostic output from a production play.
Diagnose an unexpected or undefined value
The variable is undefined
- Check the spelling and capitalization in the definition and every reference.
- Confirm that the play targets the inventory group or host whose variables you edited.
- Verify that a
vars_filespath is included by the play that needs it. - Move a value from a host-only file to the correct group file if several hosts require it.
The value is present but wrong
- Search for every definition of the variable name across playbooks, vars files, group variables, host variables, and task files.
- Check the command that launched the play for
-e; extra vars override lower sources. - Look for an earlier
set_facttask or a registered result being reused under the same name. - If several inventory groups define the key, resolve the conflict rather than relying on which group happens to load last.
An inventory edit has no effect
A run-time fact may have higher precedence than the file you changed, and cached facts can survive beyond the task that created them. Inspect the play for set_fact, check whether fact caching is enabled, and remove or rename the calculated variable when the file-based value should be authoritative.
A value changes between Ansible versions
Do not assume a third-party precedence chart applies to your installation. Compare the official precedence documentation for the exact ansible-core version, especially for set_fact, registered variables, includes, and role parameters. Then add an explicit host or extra-variable override only where the behavior is intentional.
Quick Recap
Practical rules for maintainable variables
- Use names that describe purpose, such as
app_port, rather than ambiguous names such asport. - Keep shared defaults in
group_varsand put only genuine exceptions inhost_vars. - Use
vars_filesto separate sizable environment configuration from task flow. - Reserve
set_factfor values calculated during execution; do not use it merely to duplicate inventory data. - Give registered results distinctive names, such as
package_check, so they are not confused with the value they report. - Use extra vars for a deliberate, documented override rather than as a permanent configuration store.
- When a key is defined in multiple places, document which source is expected to win and test that assumption on the target ansible-core version.
- Before a production run, add a temporary debug task to display non-sensitive effective values and remove it after validation.
Variable checklist before running a playbook
- List every variable the play references and identify its intended source.
- Confirm the selected inventory contains the expected groups and hosts.
- Check that
group_vars,host_vars, and every declaredvars_filespath is in the location Ansible loads for that inventory and play. - Search for duplicate definitions and decide which one should win.
- Inspect the command line for accidental
-evalues. - Review tasks that create
set_factvalues or register results under names used later. - For a precedence-sensitive change, consult the official hierarchy for the exact ansible-core release instead of relying on a generic chart.
- Run a safe validation with a debug task that prints only non-secret values, then deploy once the effective configuration matches your plan.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




