AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

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.

Ansible Magic Variables: Complete Reference with Examples

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
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. 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

VariableSourceValue
inventory_hostnameInventory fileName as defined
ansible_hostnameRemote systemActual hostname
ansible_fqdnRemote systemFull domain name
ansible_hostInventory/connectionIP 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

VariableDescription
inventory_hostnameHost name from inventory
ansible_hostConnection address
group_namesGroups this host belongs to
groupsAll groups and their hosts
hostvarsAll host variables (any host)
ansible_play_hostsActive hosts in current play
ansible_play_batchCurrent serial batch
play_hosts(deprecated) Use ansible_play_hosts
inventory_dirInventory file directory
playbook_dirPlaybook directory
role_pathCurrent role path
ansible_check_modeTrue if --check
ansible_versionAnsible 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.

See also

Category: troubleshooting

Watch the video: Ansible Magic Variables: Complete Reference with Examples — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home