Ansible inventory_hostname vs ansible_hostname vs ansible_fqdn (Explained)
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
Difference between Ansible inventory_hostname, ansible_hostname, ansible_host, and ansible_fqdn variables.

What is the difference between ansible_hostname vs inventory_hostname?
These two ansible internal variables sometimes confuse one for another but they're fundamentally different. I'm Luca Berton and welcome to today's episode of Ansible Pilot.ansible_hostname and ansible_fqdn
Read from the target machine hostname from the facts:
• ansible_hostname read the hostname from the facts collected during the gather_facts
• Same as the uname -n or hostname command-line
• Need gather_facts enabled, otherwise the ansible_facts variable would be unavailable to use in your playbook
• Same as hostname of the target host
• As this is based on the gather_facts step. ansible_hostname not available in ad-hoc command
inventory_hostname
Read from Ansible inventory or hosts files:
• inventory_hostname read the hostname from the inventory configuration or the hosts file. Could be different from the hostname configuration of the remote system. It could be only a name on the controller machine
• inventory_hostname is always available to use in your playbook.
• Could be different from the hostname of the target host
• Available for both playbook and ad-hoc command
See also: 10 Proven Methods to Optimize Ansible Playbook Performance
Playbook
Let me show you the difference between ansible_hostname vs inventory_hostname vs ansible_fqdn internal variables in a simple Ansible Playbook.
code
• hostnames.yml---
- name: hostnames Playbook
hosts: all
gather_facts: true
tasks:
- name: print inventory_hostname
ansible.builtin.debug:
var: inventory_hostname
- name: print ansible_hostname
ansible.builtin.debug:
var: ansible_hostname
- name: print ansible_fqdn
ansible.builtin.debug:
var: ansible_fqdn
• inventory
foo.example.com ansible_host=192.168.0.190
[all:vars]
ansible_connection=ssh
ansible_user=devops
ansible_ssh_private_key_file=~/.ssh/id_rsa
execution
ansible-pilot $ ansible-playbook -i ansible\ statements/inventory ansible\ statements/hostnames.yml
PLAY [hostnames Playbook] *****************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [foo.example.com]
TASK [print inventory_hostname] *******************************************************************
ok: [foo.example.com] => {
"inventory_hostname": "foo.example.com"
}
TASK [print ansible_hostname] *********************************************************************
ok: [foo.example.com] => {
"ansible_hostname": "Playbook"
}
TASK [print ansible_fqdn] *************************************************************************
ok: [foo.example.com] => {
"ansible_fqdn": "demo.example.com"
}
PLAY RECAP ****************************************************************************************
foo.example.com : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $
idempotency
ansible-pilot $ ansible-playbook -i ansible\ statements/inventory ansible\ statements/hostnames.yml
PLAY [hostnames Playbook] *****************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [foo.example.com]
TASK [print inventory_hostname] *******************************************************************
ok: [foo.example.com] => {
"inventory_hostname": "foo.example.com"
}
TASK [print ansible_hostname] *********************************************************************
ok: [foo.example.com] => {
"ansible_hostname": "Playbook"
}
TASK [print ansible_fqdn] *************************************************************************
ok: [foo.example.com] => {
"ansible_fqdn": "demo.example.com"
}
PLAY RECAP ****************************************************************************************
foo.example.com : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $
before execution
ansible-pilot $ ssh devops@192.168.0.190
[devops@demo ~]$ uname -a
Linux demo.example.com 4.18.0-348.el8.x86_64 #1 SMP Mon Oct 4 12:17:22 EDT 2021 x86_64 x86_64 x86_64 GNU/Linux
[devops@demo ~]$ uname -n
demo.example.com
[devops@demo ~]$ hostname
demo.example.com
[devops@demo ~]$
Conclusion
Now you know more about the Ansible internal variables ansible_hostname, inventory_hostname and ansible_fqdn.
You know how to use it based on your use case.
See also: ansible.cfg Configuration File: Complete Settings Guide (2026)
Quick Comparison
| Variable | Source | Example | Needs gather_facts |
|----------|--------|---------|-------------------|
| inventory_hostname | Inventory file | web1 | No |
| inventory_hostname_short | Inventory file (short) | web1 | No |
| ansible_hostname | Remote host (hostname) | ip-10-0-1-42 | Yes |
| ansible_fqdn | Remote DNS | ip-10-0-1-42.ec2.internal | Yes |
| ansible_host | Inventory ansible_host | 10.0.1.42 | No |
| ansible_nodename | Remote uname -n | ip-10-0-1-42 | Yes |
Example
# inventory.yml
webservers:
hosts:
web1:
ansible_host: 10.0.1.42
- debug:
msg:
- "inventory_hostname: {{ inventory_hostname }}" # web1
- "inventory_hostname_short: {{ inventory_hostname_short }}" # web1
- "ansible_host: {{ ansible_host }}" # 10.0.1.42
- "ansible_hostname: {{ ansible_hostname }}" # ip-10-0-1-42
- "ansible_fqdn: {{ ansible_fqdn }}" # ip-10-0-1-42.ec2.internal
See also: Ansible Magic Variables: Complete Reference with Examples
When to Use Each
inventory_hostname — Most common
# Referencing hosts in plays, templates, conditions
- name: Configure based on inventory name
template:
src: vhost.conf.j2
dest: "/etc/nginx/sites-enabled/{{ inventory_hostname }}.conf"
# Accessing other hosts' variables
- debug:
msg: "{{ hostvars[groups['dbservers'][0]].ansible_host }}"
ansible_hostname — Actual hostname
# When you need the real system hostname
- name: Verify hostname matches expected
assert:
that: ansible_hostname == expected_hostname
fail_msg: "Hostname mismatch!"
ansible_fqdn — DNS/certificates
# SSL certificates need FQDN
- name: Generate CSR with correct FQDN
community.crypto.openssl_csr:
path: /etc/ssl/certs/{{ ansible_fqdn }}.csr
common_name: "{{ ansible_fqdn }}"
ansible_host — Connection address
# When you need the IP/address for configs
- name: Configure app to listen on correct IP
lineinfile:
path: /etc/myapp/config.yml
regexp: '^bind_address:'
line: "bind_address: {{ ansible_host }}"
In Templates
# nginx.conf.j2
server {
server_name {{ ansible_fqdn }} {{ inventory_hostname }};
listen {{ ansible_host }}:80;
}
Common Pitfall
# inventory_hostname works WITHOUT gather_facts
- hosts: all
gather_facts: false
tasks:
- debug: msg="{{ inventory_hostname }}" # Works
- debug: msg="{{ ansible_hostname }}" # FAILS - needs facts
# Enable facts for ansible_hostname/fqdn
- hosts: all
gather_facts: true
tasks:
- debug: msg="{{ ansible_fqdn }}" # Works
FAQ
Why is ansible_hostname different from inventory_hostname?
inventory_hostname is what YOU named the host in inventory. ansible_hostname is what the HOST calls itself (output of hostname). They can differ significantly, especially in cloud environments.
Which should I use in templates?
• For file paths and Ansible references:inventory_hostname
• For DNS/SSL/network configs: ansible_fqdn
• For IP-based configs: ansible_host or ansible_default_ipv4.address
How do I set the hostname to match inventory?
- ansible.builtin.hostname:
name: "{{ inventory_hostname }}"
become: true
Related Articles
• managing inventory in Ansible • role directory layout in AnsibleCategory: troubleshooting
Watch the video: Ansible inventory_hostname vs ansible_hostname vs ansible_fqdn (Explained) — Video Tutorial