Introduction

Every time Ansible runs a playbook, it gathers facts from every host — hardware info, network configuration, OS details. For large inventories (hundreds or thousands of hosts), this adds minutes to every run.

Cache plugins solve this by storing gathered facts between playbook runs. The next run reads cached facts instead of re-gathering them, dramatically reducing execution time.

How Fact Caching Works

``` Without caching: Run 1: gather_facts (60s) → tasks (30s) = 90s Run 2: gather_facts (60s) → tasks (30s) = 90s

With caching: Run 1: gather_facts (60s) → cache facts → tasks (30s) = 90s Run 2: read cache (1s) → tasks (30s) = 31s ← 66% faster ```

Available Cache Plugins

PluginBackendSharedPersistentBest For
`memory`RAMNoNoDefault (single run)
`jsonfile`JSON filesYes*YesSimple setups
`yaml`YAML filesYes*YesHuman-readable cache
`redis`Redis serverYesYesTeams, CI/CD, Tower
`memcached`MemcachedYesNoHigh-speed, ephemeral
`mongodb`MongoDBYesYesLarge inventories
`pickle`Pickle filesYes*YesFast serialization

* File-based plugins are shared if the cache directory is on shared storage.

JSON File Cache (Simplest)

```ini

[defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts_cache fact_caching_timeout = 86400 # 24 hours in seconds ```

```bash

mkdir -p /tmp/ansible_facts_cache

ls /tmp/ansible_facts_cache/

cat /tmp/ansible_facts_cache/web1.example.com | python3 -m json.tool | head -20 ```

Setup Redis

```bash

sudo apt install redis-server # Debian/Ubuntu sudo dnf install redis # RHEL/Fedora

sudo systemctl enable --now redis

pip install redis ```

Configure Ansible

```ini

[defaults] gathering = smart fact_caching = redis fact_caching_connection = localhost:6379:0 fact_caching_timeout = 86400 fact_caching_prefix = ansible_facts_ ```

Redis with Authentication

```ini

[defaults] fact_caching = redis fact_caching_connection = redis://mypassword@redis.example.com:6379/0 fact_caching_timeout = 3600 ```

Redis with TLS

```ini fact_caching_connection = rediss://mypassword@redis.example.com:6380/0 ```

Verify Redis Cache

```bash

redis-cli KEYS "ansible_facts_*"

redis-cli GET "ansible_facts_web1.example.com" | python3 -m json.tool | head

redis-cli KEYS "ansible_facts_*" | xargs redis-cli DEL ```

Memcached Cache

```bash

sudo apt install memcached pip install python-memcached ```

```ini

[defaults] gathering = smart fact_caching = memcached fact_caching_connection = ['localhost:11211'] fact_caching_timeout = 3600 ```

Gathering Modes

The `gathering` setting controls when facts are collected:

ModeBehavior
`implicit`Always gather facts (default)
`explicit`Only gather when `gather_facts: true`
`smart`Gather only if not in cache

```ini

[defaults] gathering = smart # Required for fact caching to work ```

Complete Performance-Optimized Configuration

```ini

[defaults] gathering = smart fact_caching = redis fact_caching_connection = redis.example.com:6379:0 fact_caching_timeout = 86400 forks = 50 strategy = free host_key_checking = False

[ssh_connection] pipelining = True ssh_args = -o ControlMaster=auto -o ControlPersist=600s ```

Playbook-Level Cache Control

```yaml

  • name: Deploy config files hosts: webservers gather_facts: false tasks:
    • name: Copy config ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf

  • name: Inventory audit hosts: all gather_facts: true module_defaults: ansible.builtin.setup: gather_timeout: 30 tasks:
    • name: Report OS versions ansible.builtin.debug: msg: "{{ ansible_distribution }} {{ ansible_distribution_version }}" ```

Clearing the Cache

```bash

rm -rf /tmp/ansible_facts_cache/*

redis-cli KEYS "ansible_facts_*" | xargs redis-cli DEL

ansible-playbook site.yml --flush-cache

```

```yaml

  • name: Clear facts cache hosts: all tasks:
    • name: Flush cached facts ansible.builtin.meta: clear_facts ```

Benchmarks

Tested with 500 hosts on a standard control node:

ConfigurationTime (first run)Time (cached)Speedup
No caching4m 12s4m 12s—
JSON file4m 15s1m 38s2.6x
Redis4m 14s1m 22s3.1x
Redis + pipelining4m 14s0m 58s4.3x
No facts + Redis—0m 42s6.0x

Troubleshooting

Cache not working: ```bash

ansible-config dump | grep CACHE ansible-config dump | grep GATHERING ```

Stale facts: ```bash

ansible-playbook site.yml --flush-cache ```

Redis connection refused: ```bash

redis-cli ping # Should return PONG

sudo ss -tlnp | grep 6379 ```

Conclusion

Cache plugins are one of the easiest performance wins in Ansible. Start with JSON file caching for development, switch to Redis for production and CI/CD pipelines. Combined with `gathering = smart` and SSH pipelining, you can reduce playbook execution time by 3-6x for large inventories.