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

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 GuideAnsible inventory complete referenceAnsible loops guide

See also

Ansible group_vars & host_vars: Organize Variables by Host and Group

Category: troubleshooting

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

Browse all Ansible tutorials · AnsiblePilot Home