Skip to content

Ansible Facts — ansible_facts


Every playbook you’ve run has started with an unexplained task: TASK [Gathering Facts]. This chapter finally explains what that is, where it comes from, and how to actually use what it collects. You can even disable it.

What Are Facts?

Facts are variables Ansible automatically discovers about each managed host — its operating system, network addresses, hostname, memory, and a long list of other system details. Unlike everything else in this section so far, you don’t define facts yourself; Ansible collects them fresh, per host, at the start of a play.

Where Do Facts Come From?

That “Gathering Facts” task is a real module, ansible.builtin.setup, running implicitly at the start of every play unless you turn it off. It connects to each host, inspects the system, and stores what it finds as variables available for the rest of that run — under ansible_facts.

Printing A Fact

facts_demo.yaml
- name: Facts Demo
  hosts: servers
  tasks:
    - name: Print the OS family
      ansible.builtin.debug:
        msg: "{{ ansible_facts['os_family'] }}"
ok: [ubuntu] => {
    "msg": "Debian"
}
ok: [fedora] => {
    "msg": "RedHat"
}

Same task, same variable name, genuinely different values — because facts are collected fresh per host, and our two lab machines actually are different distributions.

Common Facts Worth Knowing

FactHolds
ansible_facts['os_family']Broad OS family (Debian, RedHat, and so on)
ansible_facts['distribution']Specific distribution name
ansible_facts['hostname']The host’s own hostname
ansible_facts['default_ipv4']['address']Primary IPv4 address
ansible_facts['memtotal_mb']Total memory, in megabytes

Note

You’ll also see some facts referenced directly as ansible_hostname, ansible_distribution, and so on — without the ansible_facts['...'] lookup. This shorthand exists for backward compatibility and still works, but ansible_facts['...'] is the current, explicit, recommended form. Expect to see both in the wild.

Disabling Fact Gathering

If a play doesn’t need any system information at all, gather_facts: false skips the automatic setup task entirely, saving a little time on every run:

- name: No Facts Needed
  hosts: servers
  gather_facts: false
  tasks:
    - name: Just print a static message
      ansible.builtin.debug:
        msg: "This play never touched facts"

Not something to reach for by default — just an option worth knowing exists once you notice a play genuinely never references any fact.

A Gotcha: Bracket Notation Is Safer Than Dot Notation

You may see facts accessed two ways: ansible_facts.os_family and ansible_facts['os_family']. Both often work — but dot notation can silently break for keys that clash with Python’s own dictionary method names, or contain characters dot notation can’t represent cleanly. Bracket notation, ansible_facts['os_family'], always works, unambiguously. Make it the default habit rather than something you only reach for when dot notation happens to fail.

Best Practices

  • Leave fact gathering enabled unless you have a specific, deliberate reason to disable it — the cost is small, and the information is frequently useful even when you didn’t plan to need it upfront.
  • Use bracket notation (ansible_facts['key']) by default, not the dot-shorthand.
  • Print facts to explore what’s available before hardcoding a value. If you’re about to hardcode an OS-specific path or package name, check whether a fact could tell you the right value dynamically instead.
Last updated on