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 facts: Gather, Use, and Create Custom Facts

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

Complete guide to Ansible facts. Learn how to gather system facts, use them in playbooks, create custom facts, cache facts for performance, and use set_fact.

Facts are variables automatically discovered about remote hosts — OS, IP addresses, memory, CPU, disks, and more. They're the foundation of conditional logic and cross-platform playbooks.

Gathering Facts

# Facts are gathered automatically at play start
- hosts: all
  # gather_facts: true  ← default
  tasks:
    - ansible.builtin.debug:
        msg: "{{ ansible_hostname }} runs {{ ansible_distribution }} {{ ansible_distribution_version }}"

See All Facts

# Dump all facts for a host
ansible host -m setup

# Filter specific facts ansible host -m setup -a "filter=ansible_distribution*" ansible host -m setup -a "filter=ansible_default_ipv4" ansible host -m setup -a "filter=ansible_memory_mb"

See also: Ansible gather_facts & ansible_facts: Access Host Information (Guide)

Most Useful Facts

Operating System

ansible_distribution: "Ubuntu"           # Ubuntu, CentOS, Debian, RedHat, Amazon
ansible_distribution_version: "24.04"
ansible_distribution_major_version: "24"
ansible_distribution_release: "noble"
ansible_os_family: "Debian"              # Debian, RedHat, Suse, Darwin, Windows
ansible_system: "Linux"                  # Linux, Darwin, Windows
ansible_architecture: "x86_64"
ansible_kernel: "6.8.0-45-generic"

Network

ansible_hostname: "web01"
ansible_fqdn: "web01.example.com"
ansible_default_ipv4:
  address: "10.0.1.10"
  interface: "eth0"
  gateway: "10.0.1.1"
  netmask: "255.255.255.0"
ansible_all_ipv4_addresses: ["10.0.1.10", "172.17.0.1"]

Hardware

ansible_memtotal_mb: 8192
ansible_memfree_mb: 4096
ansible_processor_vcpus: 4
ansible_processor: ["Intel(R) Xeon(R) CPU E5-2686 v4"]
ansible_devices:
  sda: { size: "100.00 GB", model: "Virtual disk" }

Timestamps

ansible_date_time:
  iso8601: "2026-04-13T01:00:00Z"
  date: "2026-04-13"
  hour: "01"
  tz: "UTC"

Using Facts for Conditional Logic

OS-Specific Tasks

- name: Install packages (Debian)
  ansible.builtin.apt:
    name: "{{ packages }}"
    state: present
    update_cache: true
  when: ansible_os_family == "Debian"

- name: Install packages (RedHat) ansible.builtin.dnf: name: "{{ packages }}" state: present when: ansible_os_family == "RedHat"

Memory-Based Configuration

- name: Configure JVM heap based on available memory
  ansible.builtin.template:
    src: jvm.options.j2
    dest: /etc/myapp/jvm.options
  vars:
    heap_size_mb: "{{ (ansible_memtotal_mb * 0.5) | int }}"

Version-Specific Logic

- name: Use new syntax for Ubuntu 24+
  ansible.builtin.command: new-command --v2
  when: >
    ansible_distribution == "Ubuntu" and
    ansible_distribution_major_version | int >= 24

See also: Ansible Fix 'VARIABLE IS NOT DEFINED' Error: Undefined Variables

Custom Facts (Local Facts)

Create /etc/ansible/facts.d/.fact files on remote hosts:

# Deploy a custom fact file
- name: Deploy application facts
  ansible.builtin.copy:
    content: |
      [application]
      name=myapp
      version=2.5.0
      environment=production
      deployed_by=ansible
      deployed_at={{ ansible_date_time.iso8601 }}
    dest: /etc/ansible/facts.d/myapp.fact
    mode: '0644'

# Re-gather facts to pick up the new file - name: Reload facts ansible.builtin.setup: filter: ansible_local

# Use the custom fact - ansible.builtin.debug: msg: "App version: {{ ansible_local.myapp.application.version }}"

JSON Custom Facts

- name: Deploy JSON fact
  ansible.builtin.copy:
    content: |
      {
        "app_version": "2.5.0",
        "features": ["api", "worker", "scheduler"],
        "config": {
          "port": 8080,
          "workers": 4
        }
      }
    dest: /etc/ansible/facts.d/myapp.fact
    mode: '0644'

# Access: ansible_local.myapp.app_version # Access: ansible_local.myapp.config.port

Executable Fact Scripts

#!/bin/bash
# /etc/ansible/facts.d/disk_usage.fact
# Must output JSON
echo "{"
echo "  \"root_usage_percent\": $(df / --output=pcent | tail -1 | tr -d ' %'),"
echo "  \"data_usage_percent\": $(df /data --output=pcent 2>/dev/null | tail -1 | tr -d ' %' || echo 0)"
echo "}"
# Access: ansible_local.disk_usage.root_usage_percent

Fact Caching

Speed up playbooks by caching facts:

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

# Or use Redis # fact_caching = redis # fact_caching_connection = localhost:6379

See also: ansible.builtin.set_fact Module: Set Variables Dynamically (Complete Guide)

Disable Fact Gathering

# Skip fact gathering for faster execution
- hosts: all
  gather_facts: false
  tasks:
    - name: Simple task that doesn't need facts
      ansible.builtin.ping:

# Gather facts later if needed - name: Gather facts now ansible.builtin.setup: when: need_facts | default(false)

set_fact vs Gathered Facts

# Gathered facts: automatic system info
# set_fact: custom runtime variables

- name: Get app version ansible.builtin.command: /opt/app/bin/version register: version_output changed_when: false

- name: Create clean fact from output ansible.builtin.set_fact: app_version: "{{ version_output.stdout | trim }}" app_needs_upgrade: "{{ version_output.stdout is version('2.0', '<') }}"

Accessing Facts from Other Hosts

# Use hostvars to get facts from any host in the play
- name: Configure app to connect to database
  ansible.builtin.template:
    src: db-config.j2
    dest: /etc/myapp/database.yml
  vars:
    db_host: "{{ hostvars[groups['databases'][0]].ansible_default_ipv4.address }}"
    db_memory: "{{ hostvars[groups['databases'][0]].ansible_memtotal_mb }}"

FAQ

How do I see what facts are available?

Run ansible hostname -m setup to see all facts. Use ansible hostname -m setup -a "filter=ansible_memory*" to search for specific facts. Facts follow the pattern ansible__.

Why is fact gathering slow?

Fact gathering runs setup on every host, collecting hardware, network, and OS info. Speed it up with gather_subset to collect only what you need:

- hosts: all
  gather_facts: true
  gather_subset:
    - network
    - '!hardware'    # Skip slow hardware detection

Can I use facts in inventory?

No — facts are gathered at runtime, not during inventory parsing. For inventory-time variables, use group_vars, host_vars, or dynamic inventory scripts.

What's the difference between ansible_facts and top-level facts?

Both work. ansible_facts['distribution'] and ansible_distribution reference the same data. The ansible_facts dictionary is the canonical source; top-level variables are injected for convenience.

Conclusion

Facts are Ansible's discovery layer — they tell your playbooks what they're working with. Use gathered facts for conditional logic and cross-platform support, custom facts for application metadata, and fact caching for performance. Every serious Ansible deployment relies on facts.

Related Articles

Ansible set_fact vs vars vs extra_varsAnsible Conditionals (when)Ansible Variable Precedence GuideAnsible Inventory Guideansible_hostname vs inventory_hostname vs ansible_fqdnAnsible gather_facts & ansible_facts Guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home