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 gather_facts & ansible_facts: Access Host Information (Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

Complete guide to Ansible gather_facts and ansible_facts. Access OS type, IP addresses, memory, disk space, and hardware info.

Ansible facts are system properties collected from managed hosts — OS type, IP addresses, memory, CPU, disk space, and more. They're gathered automatically at the start of each play and available as variables throughout your playbook.

How Facts Work

- name: Show facts
  hosts: all
  # gather_facts: true  (default — happens automatically)
  tasks:
    - ansible.builtin.debug:
        msg: |
          OS: {{ ansible_distribution }} {{ ansible_distribution_version }}
          IP: {{ ansible_default_ipv4.address }}
          Memory: {{ ansible_memtotal_mb }} MB
          CPUs: {{ ansible_processor_vcpus }}

See also: Ansible Facts: Gather, Use, and Create Custom Facts (Complete Guide)

Most Used Facts

# Operating system
ansible_distribution          # "Ubuntu", "CentOS", "RedHat"
ansible_distribution_version  # "24.04", "9.3"
ansible_distribution_release  # "noble", "Plow"
ansible_os_family            # "Debian", "RedHat", "Suse"
ansible_kernel               # "6.8.0-41-generic"
ansible_architecture         # "x86_64", "aarch64"

# Network ansible_default_ipv4.address # Primary IPv4 ansible_default_ipv4.interface # "eth0", "ens3" ansible_all_ipv4_addresses # All IPv4 addresses (list) ansible_hostname # Short hostname ansible_fqdn # Fully qualified domain name

# Hardware ansible_memtotal_mb # Total RAM in MB ansible_memfree_mb # Free RAM in MB ansible_processor_vcpus # Number of CPUs ansible_devices # Disk devices

# Python ansible_python_version # "3.11.5" ansible_python.executable # "/usr/bin/python3"

Conditional Tasks with Facts

# OS-specific tasks
- name: Install on Debian
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian"

- name: Install on RedHat ansible.builtin.dnf: name: nginx state: present when: ansible_os_family == "RedHat"

# Version checks - name: Only on Ubuntu 22.04+ ansible.builtin.debug: msg: "Running on modern Ubuntu" when: - ansible_distribution == "Ubuntu" - ansible_distribution_version is version("22.04", ">=")

# Memory-based decisions - name: Configure swap if low memory ansible.builtin.include_tasks: setup-swap.yml when: ansible_memtotal_mb < 2048

See also: Generate Clean YAML Output from Ansible Facts

Disable Fact Gathering

# Skip facts for faster execution
- name: Simple task (no facts needed)
  hosts: all
  gather_facts: false
  tasks:
    - name: Copy file
      ansible.builtin.copy:
        src: config.yml
        dest: /etc/app/config.yml

When to disable: Tasks that don't use any ansible_ variables. Saves 1-5 seconds per host.

Gather Specific Facts Only

# Only gather network facts
- name: Network info only
  hosts: all
  gather_facts: false
  tasks:
    - name: Gather network subset
      ansible.builtin.setup:
        gather_subset:
          - network

- ansible.builtin.debug: msg: "IP: {{ ansible_default_ipv4.address }}"

Available subsets: all, min, hardware, network, virtual, ohai, facter

# Exclude slow subsets
- ansible.builtin.setup:
    gather_subset:
      - "!hardware"    # Skip hardware detection (slow on some systems)

See also: Ansible facts: Gather, Use, and Create Custom Facts

Filter Facts

# Only get facts matching a pattern
- ansible.builtin.setup:
    filter: "ansible_mem*"
  register: mem_facts

# Result: only ansible_memtotal_mb, ansible_memfree_mb, etc.

Custom Facts (Local Facts)

Place .fact files on managed hosts at /etc/ansible/facts.d/:

# /etc/ansible/facts.d/app.fact
[general]
app_version=2.5.1
environment=production
maintainer=ops-team
# Deploy custom fact
- name: Create facts directory
  ansible.builtin.file:
    path: /etc/ansible/facts.d
    state: directory
    mode: '0755'

- name: Deploy application fact ansible.builtin.copy: content: | [app] version={{ app_version }} deploy_date={{ ansible_date_time.date }} dest: /etc/ansible/facts.d/myapp.fact mode: '0644'

# Access custom facts - name: Re-gather facts ansible.builtin.setup:

- name: Show custom fact ansible.builtin.debug: msg: "App version: {{ ansible_local.myapp.app.version }}"

Fact Caching

# ansible.cfg
[defaults]
gathering = smart              # Only gather if not cached
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600    # Cache for 1 hour

Other backends: redis, memcached, yaml, jsonfile

set_fact: Create Runtime Facts

- name: Calculate derived fact
  ansible.builtin.set_fact:
    swap_size_mb: "{{ ansible_memtotal_mb * 2 }}"
    is_production: "{{ 'prod' in inventory_hostname }}"

- name: Use derived fact ansible.builtin.debug: msg: "Swap: {{ swap_size_mb }}MB, Production: {{ is_production }}"

View All Facts

# From command line
ansible hostname -m setup

# Filter from command line ansible hostname -m setup -a "filter=ansible_distribution*"

# In a playbook — dump all facts
- name: Save facts to file
  ansible.builtin.copy:
    content: "{{ ansible_facts | to_nice_json }}"
    dest: "/tmp/facts_{{ inventory_hostname }}.json"
  delegate_to: localhost

Practical Examples

Inventory Report

- name: Generate server report
  hosts: all
  tasks:
    - name: Write report line
      ansible.builtin.lineinfile:
        path: /tmp/server-report.csv
        line: "{{ inventory_hostname }},{{ ansible_distribution }},{{ ansible_distribution_version }},{{ ansible_default_ipv4.address }},{{ ansible_memtotal_mb }}MB,{{ ansible_processor_vcpus }}CPU"
        create: true
      delegate_to: localhost

OS-Agnostic Package Variable

vars:
  package_names:
    Debian:
      web: apache2
      db: postgresql
    RedHat:
      web: httpd
      db: postgresql-server

tasks: - name: Install web server ansible.builtin.package: name: "{{ package_names[ansible_os_family].web }}" state: present

FAQ

What's the difference between ansible_facts and ansible_ variables?

They're the same data. ansible_facts['distribution'] and ansible_distribution both work. The ansible_facts dictionary is the modern format; the flat ansible_* variables are injected for backward compatibility (controlled by INJECT_FACTS_AS_VARS in ansible.cfg).

How do I speed up fact gathering?

Set gather_facts: false when you don't need facts Use gather_subset to collect only what you need Enable fact caching (gathering = smart) Exclude slow subsets: gather_subset: ['!hardware']

How do I get facts from another host?

Use hostvars:

- ansible.builtin.debug:
    msg: "DB server IP: {{ hostvars['dbserver'].ansible_default_ipv4.address }}"

Why are facts empty or missing?

The remote host may lack Python, or gather_facts: false is set. Check that Python is installed and the setup module can run: ansible hostname -m setup.

Conclusion

Facts are the foundation of dynamic, OS-aware playbooks. Use them for conditional tasks, template variables, and inventory reporting. Disable gathering when not needed for speed, cache facts for large inventories, and create custom facts for application-specific metadata.

Related Articles

Ansible inventory_hostname vs ansible_hostnameAnsible set_fact vs vars vs extra_varsAnsible Performance Tuning

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home