Ansible Magic Variables: Complete Reference with Examples
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
Complete reference for Ansible magic variables. Use inventory_hostname, hostvars, groups, play_hosts, ansible_facts, and special variables in playbooks.

How to Use Ansible Magic Variables in Ansible Playbook
I'm going to show you a live Playbook and some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.See also: Ansible playbook_dir: Get Current Playbook Path (Magic Variable Guide)
Ansible Magic Variables
How to Ansible Magic Variables in Ansible Playbook. The good news is that Ansible provides some internal variables that come out of the box with some information such as running the Ansible version, inventory details, or execution options. Some examples: •playbook_dir
The path to the directory of the playbook that was passed to the ansible-playbook command line
• inventory_dir
The directory of the inventory source in which the inventory_hostname was first defined
• inventory_file
The file name of the inventory source in which the inventory_hostname was first defined
• inventory_hostname
The inventory name for the 'current' host is being iterated over in the play
• ansible_check_mode / ansible_diff_mode
Boolean that indicates if we are in check/diff mode or not
• ansible_version
Dictionary/map that contains information about the currently running version of ansible, it has the following keys: full, major, minor, revision and string.
Links
The full list is available on the official Ansible website Magic variables## Playbook
How to use Ansible Magic Variables in Ansible Playbook?
Let's see in action some of the most common Ansible Magic Variables in an Ansible Playbook.
I'm going to display the current value of the following variables:
• ansible_config_file
The full path of the used Ansible configuration file playbook_dir
The path to the directory of the playbook was passed to the ansible-playbook command line.
• inventory_dir
The directory of the inventory source in which the inventory_hostname was first defined
• inventory_file
The file name of the inventory source in which the inventory_hostname was first defined
• ansible_check_mode
Boolean that indicates if we are in check mode or not
• ansible_diff_mode
Boolean that indicates if we are in diff mode or not
• ansible_forks
Integer reflecting the number of maximum forks available to this run
• ansible_verbosity
Current verbosity setting for Ansible
• inventory_hostname
The inventory name for the 'current' host is being iterated over in the play
• ansible_play_hosts
List of hosts in the current play run, not limited by the serial. Failed/Unreachable hosts are excluded from this list.
• ansible_version
Dictionary/map that contains information about the currently running version of ansible, it has the following keys: full, major, minor, revision and string.
code
---
- name: magic vars Playbook
hosts: all
gather_facts: false
tasks:
- name: magic variable
ansible.builtin.debug:
var: "{{ item }}"
loop:
- ansible_config_file
- playbook_dir
- inventory_dir
- inventory_file
- ansible_check_mode
- ansible_diff_mode
- ansible_forks
- ansible_verbosity
- inventory_hostname
- ansible_play_hosts
- ansible_version
execution
$ ansible-playbook -i virtualmachines/demo/inventory variables/magic.yml
PLAY [magic vars Playbook] ****************************************************************************
TASK [magic variable] *****************************************************************************
ok: [demo.example.com] => (item=ansible_config_file) => {
"ansible_config_file": null,
"ansible_loop_var": "item",
"item": "ansible_config_file"
}
ok: [demo.example.com] => (item=playbook_dir) => {
"ansible_loop_var": "item",
"item": "playbook_dir",
"playbook_dir": "/Users/lberton/prj/github/ansible-pilot/variables"
}
ok: [demo.example.com] => (item=inventory_dir) => {
"ansible_loop_var": "item",
"inventory_dir": "/Users/lberton/prj/github/ansible-pilot/virtualmachines/Playbook",
"item": "inventory_dir"
}
ok: [demo.example.com] => (item=inventory_file) => {
"ansible_loop_var": "item",
"inventory_file": "/Users/lberton/prj/github/ansible-pilot/virtualmachines/demo/inventory",
"item": "inventory_file"
}
ok: [demo.example.com] => (item=ansible_check_mode) => {
"ansible_check_mode": false,
"ansible_loop_var": "item",
"item": "ansible_check_mode"
}
ok: [demo.example.com] => (item=ansible_diff_mode) => {
"ansible_diff_mode": false,
"ansible_loop_var": "item",
"item": "ansible_diff_mode"
}
ok: [demo.example.com] => (item=ansible_forks) => {
"ansible_forks": 5,
"ansible_loop_var": "item",
"item": "ansible_forks"
}
ok: [demo.example.com] => (item=ansible_verbosity) => {
"ansible_loop_var": "item",
"ansible_verbosity": 0,
"item": "ansible_verbosity"
}
ok: [demo.example.com] => (item=inventory_hostname) => {
"ansible_loop_var": "item",
"inventory_hostname": "demo.example.com",
"item": "inventory_hostname"
}
ok: [demo.example.com] => (item=ansible_play_hosts) => {
"ansible_loop_var": "item",
"ansible_play_hosts": [
"demo.example.com"
],
"item": "ansible_play_hosts"
}
ok: [demo.example.com] => (item=ansible_version) => {
"ansible_loop_var": "item",
"ansible_version": {
"full": "2.12.5",
"major": 2,
"minor": 12,
"revision": 5,
"string": "2.12.5"
},
"item": "ansible_version"
}
PLAY RECAP ****************************************************************************************
demo.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
See also: 10 Proven Methods to Optimize Ansible Playbook Performance
Conclusion
Now you know how to use the Ansible Magic Variables in Ansible Playbook. You know how to use it based on your use case.
Key Magic Variables
- debug:
msg:
- "Hostname: {{ inventory_hostname }}"
- "Short name: {{ inventory_hostname_short }}"
- "All groups: {{ group_names }}"
- "Play hosts: {{ ansible_play_hosts }}"
- "Batch hosts: {{ ansible_play_batch }}"
- "Play name: {{ ansible_play_name }}"
- "Role name: {{ ansible_role_name | default('none') }}"
See also: ansible.cfg Configuration File: Complete Settings Guide (2026)
hostvars (Access Other Host Data)
# Access another host's variables
- debug:
msg: "DB host IP: {{ hostvars['db1'].ansible_host }}"
# Use in template
- template:
src: app.conf.j2
dest: /etc/myapp/app.conf
# In template:
# db_host={{ hostvars[groups['dbservers'][0]].ansible_host }}
groups (All Inventory Groups)
- debug:
msg:
- "Web servers: {{ groups['webservers'] }}"
- "All hosts: {{ groups['all'] }}"
- "Ungrouped: {{ groups['ungrouped'] | default([]) }}"
# Generate config from group
- template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
# In template:
# {% for host in groups['webservers'] %}
# server {{ host }} {{ hostvars[host].ansible_host }}:80
# {% endfor %}
inventory_hostname vs ansible_hostname
| Variable | Source | Value |
|----------|--------|-------|
| inventory_hostname | Inventory file | Name as defined |
| ansible_hostname | Remote system | Actual hostname |
| ansible_fqdn | Remote system | Full domain name |
| ansible_host | Inventory/connection | IP or hostname to connect |
Play Context Variables
- debug:
msg:
- "Play hosts: {{ ansible_play_hosts }}" # All hosts in play
- "Current batch: {{ ansible_play_batch }}" # Current serial batch
- "First host: {{ ansible_play_hosts[0] }}"
- "Am I first: {{ inventory_hostname == ansible_play_hosts[0] }}"
- "Host index: {{ ansible_play_hosts.index(inventory_hostname) }}"
Role Variables
# Inside a role:
- debug:
msg:
- "Role name: {{ ansible_role_name }}"
- "Role path: {{ role_path }}"
- "Role dir: {{ role_path }}/files"
- copy:
src: "{{ role_path }}/files/config.yml"
dest: /etc/myapp/config.yml
Loop Variables (with extended)
- debug:
msg: "{{ ansible_loop.index }} of {{ ansible_loop.length }}"
loop: [a, b, c]
loop_control:
extended: true
# ansible_loop.index, .index0, .first, .last, .length, .previtem, .nextitem
Practical Examples
Dynamic load balancer config
{% for host in groups['webservers'] %}
server {{ host }} {{ hostvars[host].ansible_host }}:{{ hostvars[host].http_port | default(80) }} check
{% endfor %}
Run on first host only
- command: /opt/migrate.sh
when: inventory_hostname == ansible_play_hosts[0]
Cross-group references
- set_fact:
db_ip: "{{ hostvars[groups['dbservers'][0]].ansible_host }}"
cache_ip: "{{ hostvars[groups['cache'][0]].ansible_host }}"
All Magic Variables
| Variable | Description |
|----------|-------------|
| inventory_hostname | Host name from inventory |
| ansible_host | Connection address |
| group_names | Groups this host belongs to |
| groups | All groups and their hosts |
| hostvars | All host variables (any host) |
| ansible_play_hosts | Active hosts in current play |
| ansible_play_batch | Current serial batch |
| play_hosts | (deprecated) Use ansible_play_hosts |
| inventory_dir | Inventory file directory |
| playbook_dir | Playbook directory |
| role_path | Current role path |
| ansible_check_mode | True if --check |
| ansible_version | Ansible version info |
FAQ
How do I access facts from another host?
Use hostvars: hostvars['other_host'].ansible_default_ipv4.address. The other host must be in the play or have cached facts.
Why is hostvars empty for a host?
Facts are gathered per-play. If the host hasn't been contacted yet, only inventory variables are available. Use delegate_facts or run setup module first.
Key Magic Variables
# Current host being processed
{{ inventory_hostname }} # web1.example.com
{{ inventory_hostname_short }} # web1
# All groups and hosts
{{ groups['webservers'] }} # ['web1', 'web2']
{{ groups['all'] }} # All hosts
{{ group_names }} # Groups current host belongs to
# Host variables across hosts
{{ hostvars['web1']['ansible_host'] }}
{{ hostvars[inventory_hostname]['ansible_facts']['os_family'] }}
# Play context
{{ play_hosts }} # All hosts in current play
{{ ansible_play_hosts }} # Hosts not yet failed
{{ ansible_play_batch }} # Current batch (with serial)
# Role context
{{ role_name }} # Current role name
{{ role_path }} # Path to current role
inventory_hostname vs ansible_hostname
# inventory_hostname — from inventory file (always available)
{{ inventory_hostname }} # "web1" (what you defined)
# ansible_hostname — from facts (requires gather_facts)
{{ ansible_hostname }} # "ip-10-0-1-10" (actual hostname on the machine)
hostvars (Cross-Host Access)
# Get another host's IP
- debug:
msg: "DB is at {{ hostvars['db1']['ansible_host'] }}"
# Generate config with all webserver IPs
- template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
# In template:
# {% for host in groups['webservers'] %}
# server {{ host }} {{ hostvars[host]['ansible_default_ipv4']['address'] }}:80
# {% endfor %}
groups Variable
# Check if host is in a group
- debug: msg="This is a webserver"
when: "'webservers' in group_names"
# Count hosts in group
- debug:
msg: "{{ groups['webservers'] | length }} webservers"
# First host in group (for run_once patterns)
- debug: msg="Primary DB"
when: inventory_hostname == groups['dbservers'][0]
ansible_facts
# After gather_facts
{{ ansible_facts['os_family'] }} # Debian
{{ ansible_facts['distribution'] }} # Ubuntu
{{ ansible_facts['distribution_version'] }}# 24.04
{{ ansible_facts['default_ipv4']['address'] }} # 10.0.1.10
{{ ansible_facts['memtotal_mb'] }} # 8192
{{ ansible_facts['processor_vcpus'] }} # 4
Environment and Paths
{{ ansible_env.HOME }} # Remote user's home
{{ ansible_env.PATH }} # Remote PATH
{{ playbook_dir }} # Directory of playbook
{{ inventory_dir }} # Directory of inventory
{{ ansible_config_file }} # Path to ansible.cfg
FAQ
How to see all magic variables?
- debug: var=vars # Shows everything available
Can I override magic variables?
Some can be overridden (like ansible_host). Core ones like inventory_hostname cannot.
hostvars empty for some hosts?
Facts are only available after gather_facts runs on that host. Use setup or ensure the host is in the same play.
Related Articles
• Ansible Check Mode Guide • Ansible inventory complete reference • Ansible loops guideSee also
• Ansible group_vars & host_vars: Organize Variables by Host and GroupCategory: troubleshooting
Watch the video: Ansible Magic Variables: Complete Reference with Examples — Video Tutorial