Ansible set_fact: Create & Set Runtime Variables (Complete Guide)
By Luca Berton · Published 2024-01-01 · Category: linux-administration
How to use ansible.builtin.set_fact to create variables at runtime. Set facts from task output, conditionals, loops, and registered variables.
Ansible set_fact: Create & Set Runtime Variables (Complete Guide)
The ansible.builtin.set_fact module creates or modifies variables during playbook execution. Unlike static variables defined in vars files, set_fact variables are computed at runtime based on task results, conditions, and gathered facts.
See also: Ansible set_fact vs vars vs extra_vars: Variable Types Compared
Basic Usage
---
- name: set_fact examples
hosts: all
tasks:
- name: Set a simple fact
ansible.builtin.set_fact:
app_env: production
app_port: 8080
- name: Use the fact
ansible.builtin.debug:
msg: "Running {{ app_env }} on port {{ app_port }}"
Set Facts from Registered Output
- name: Get disk usage
ansible.builtin.shell: df -h / | tail -1 | awk '{print $5}' | tr -d '%'
register: disk_cmd
changed_when: false
- name: Set disk usage fact
ansible.builtin.set_fact:
disk_usage_percent: "{{ disk_cmd.stdout | int }}"
disk_is_full: "{{ disk_cmd.stdout | int > 85 }}"
- name: Alert if disk is full
ansible.builtin.debug:
msg: "WARNING: Disk is {{ disk_usage_percent }}% full!"
when: disk_is_full | bool
See also: Ansible include_vars: Load Variables from Files Dynamically (Complete Guide)
Set Facts from Gathered Facts
- name: Derive facts from system info
ansible.builtin.set_fact:
is_debian: "{{ ansible_os_family == 'Debian' }}"
is_rhel: "{{ ansible_os_family == 'RedHat' }}"
total_memory_gb: "{{ (ansible_memtotal_mb / 1024) | round(1) }}"
primary_ip: "{{ ansible_default_ipv4.address }}"
short_hostname: "{{ ansible_hostname }}"
- name: Configure based on OS
ansible.builtin.debug:
msg: "{{ short_hostname }} — {{ total_memory_gb }}GB RAM — {{ primary_ip }}"
Conditional set_fact
- name: Set environment-specific variables
ansible.builtin.set_fact:
db_host: "{{ 'db-prod.example.com' if env == 'production' else 'db-staging.example.com' }}"
worker_count: "{{ 8 if env == 'production' else 2 }}"
debug_mode: "{{ env != 'production' }}"
# Or using when conditions:
- name: Set production facts
ansible.builtin.set_fact:
db_host: db-prod.example.com
worker_count: 8
when: env == 'production'
- name: Set staging facts
ansible.builtin.set_fact:
db_host: db-staging.example.com
worker_count: 2
when: env == 'staging'
See also: Ansible set_fact Module: Set Variables Dynamically (Complete Guide 2026)
Set Facts with Loops
- name: Build server list from inventory
ansible.builtin.set_fact:
web_servers: "{{ groups['webservers'] | map('extract', hostvars, 'ansible_host') | list }}"
- name: Build comma-separated list
ansible.builtin.set_fact:
allowed_ips: "{{ groups['trusted'] | map('extract', hostvars, 'ansible_default_ipv4') | map(attribute='address') | join(',') }}"
Accumulate Values in a Loop
- name: Initialize list
ansible.builtin.set_fact:
healthy_hosts: []
- name: Check each host and accumulate healthy ones
ansible.builtin.set_fact:
healthy_hosts: "{{ healthy_hosts + [item] }}"
loop: "{{ groups['webservers'] }}"
when: hostvars[item].health_check.status == 200
Cacheable Facts
By default, set_fact variables only live during the current play. Use cacheable: true to persist them across plays (requires fact caching):
- name: Set cacheable fact
ansible.builtin.set_fact:
last_deploy_time: "{{ ansible_date_time.iso8601 }}"
cacheable: true
# ansible.cfg — enable fact caching
[defaults]
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 86400
Set Facts from API Responses
- name: Get application version from API
ansible.builtin.uri:
url: https://api.example.com/version
return_content: true
register: api_response
- name: Set version facts
ansible.builtin.set_fact:
app_version: "{{ (api_response.content | from_json).version }}"
app_build: "{{ (api_response.content | from_json).build_number }}"
Set Complex Data Structures
- name: Set dictionary fact
ansible.builtin.set_fact:
database_config:
host: "{{ db_host }}"
port: 5432
name: "{{ app_name }}_{{ env }}"
max_connections: "{{ 200 if env == 'production' else 20 }}"
- name: Set list fact
ansible.builtin.set_fact:
required_packages:
- nginx
- postgresql-client
- "{{ 'python3-pip' if ansible_os_family == 'Debian' else 'python3-pip' }}"
set_fact vs vars vs register
| Feature | set_fact | vars | register | |---------|----------|------|----------| | When set | During task execution | Before play starts | After task runs | | Dynamic | ✅ Yes | ❌ No (Jinja2 evaluated once) | ✅ Yes | | Scope | Host-level, rest of play | Play/role level | Task-level, rest of play | | Cacheable | ✅ With cacheable: true | ❌ No | ❌ No | | Overrides vars | ✅ Higher precedence | — | ❌ No | | Use case | Computed values | Static config | Task output |
FAQ
What is ansible set_fact?
ansible.builtin.set_fact creates variables at runtime during playbook execution. Unlike vars, set_fact values are computed dynamically and can depend on task results, gathered facts, and conditions.
What is the difference between set_fact and register?
register captures the output of a specific task (stdout, rc, etc.). set_fact creates arbitrary variables with any value. Use register to capture command output, then set_fact to extract and transform what you need.
Do set_fact variables persist across plays?
By default, no — they're available for the rest of the current play only. Use cacheable: true with fact caching enabled to persist across plays and even playbook runs.
Can I use set_fact with loops?
Yes. set_fact executes for each loop iteration. To accumulate values, append to a list: set_fact: my_list: "{{ my_list + [item] }}". Initialize the list first with an empty [].
What precedence does set_fact have?
set_fact has high precedence (level 19 of 22) — it overrides vars, vars_files, group_vars, and role defaults. Only include_params, role params, and extra_vars (-e) override set_fact.
Conclusion
ansible.builtin.set_fact is essential for dynamic playbooks that adapt based on runtime data. Use it to compute variables from command output, API responses, and system facts. Combine with register, conditionals, and loops for powerful automation logic.
Related Articles
• Ansible Variables: Complete Guide • Ansible register: Capture Task Output • Ansible Magic Variables: Complete Reference • Ansible debug Module: Print VariablesCategory: linux-administration