While I'm using Ansible for quite some time, I'm not sure I really understand the differences between a variable and a fact.

Would it be any difference doing

- set_fact:
    nginx_ssl: /etc/nginx/ssl
    nginx_conf_file: /etc/nginx/nginx.conf


    nginx_ssl: /etc/nginx/ssl
    nginx_conf_file: /etc/nginx/nginx.conf

Could someone explain me, possibly with an example where it really make a difference ?

3 Answers 3


Ansible facts are data collected about the (target) systems on which Ansible takes actions. They are variables, but set by Ansible (in a way like system defined variables). They are collected during Gathering Facts stage of a playbook run, and it is controlled by the gather_facts setting. Ansible calls this variables discovered from systems. That said, it is possible to set custom facts also.

Some examples are:

  • ansible_hostname - the FQDN of the target system
  • ansible_os_family - the Operating System family of target system (RedHat, Debian, etc.)

The other variables are the ones we can set as per our requirement (in a way like user defined variables).

Some examples are:

  • my_fav_fruits: [ 'orange', 'apple', 'banana' ] - yours might differ.
  • config_dir: '/etc/my_app/conf.d' - for my application configuration files.


Updating answer to make it relevant to the edit(s) made in question.

As @Bruce Becker's answer rightly pointed out, there is a difference in the precedence of variables set with set_fact. Also variables that need to be set at "run time" can be set this way. Without further explanation, taking your example variables, if I create a play like below:

- hosts: localhost
    nginx_ssl: '/etc/nginx/ssl'
    nginx_conf_file: '/etc/nginx/nginx.conf'

  - name: set nginx path to /opt when running on Debian
      nginx_ssl: '/opt/nginx/ssl'
      nginx_conf_file: '/opt/nginx/nginx.conf'
    when: ansible_distribution == 'Debian'
  - debug:
      msg: 'ssl: {{ nginx_ssl }} and conf: {{ nginx_conf_file }}'

Then the set_fact variables will take precedence (on Debian) and output will be:

"msg": "ssl: /opt/nginx/ssl and conf: /opt/nginx/nginx.conf"

On other distributions, it will be what was declared in vars:.

  • Understood the context now. I updated my answer too.
    – seshadri_c
    Commented Sep 12, 2020 at 11:14
  • 1
    "On other distributions, it will be what was declared in vars:." I don't understand this statement. Why whould it be different on other distributions like Redhat for example? Commented Feb 25, 2022 at 16:44
  • The vars declared in the vars: section of the play have lower precedence than set_fact, so it will be what was declared under vars:, unless it is overridden with set_fact again for Redhat,
    – seshadri_c
    Commented Mar 3, 2022 at 15:06

Not to contradict anything written in @Ceshadri_C's answer, but to focus more on the difference between facts and variables - perhaps the variable precedence page could be of greater insight.

The difference between facts and variables set is defined by their precedence, i.e. all variables are important, but some variables are more important than others. In your case, the same variable set as a fact (priority 19) would take precedence declared as a variable in a task (priority 17) or play (priority 12).


Facts are also made available to subsequent plays. Variables are not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.