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
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
inventory_dir
inventory_file
inventory_hostname
ansible_check_mode/ansible_diff_mode
ansible_version
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 path to the directory of the playbook was passed to the ansible-playbook command line.
inventory_dir
inventory_file
ansible_check_mode
ansible_diff_mode
ansible_forks
ansible_verbosity
inventory_hostname
ansible_play_hosts
ansible_version
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_versionexecution
$ 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=0See 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.ymlLoop 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, .nextitemPractical 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 roleinventory_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'] }} # 4Environment 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.cfgFAQ
How to see all magic variables?
- debug: var=vars # Shows everything availableCan 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
See also
Category: troubleshooting
Watch the video: Ansible Magic Variables: Complete Reference with Examples — Video Tutorial