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 Performance Tuning: Speed Up Playbooks 10x

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

Complete Ansible performance tuning guide. Speed up playbooks with pipelining, increased forks, fact caching, async tasks, free strategy, Mitogen, and profile.

Default Ansible settings prioritize safety over speed. With the right tuning, you can make playbooks 2-10x faster without sacrificing reliability.

Quick Wins (ansible.cfg)

[defaults]
forks = 50                    # Default: 5 — process 50 hosts in parallel
gathering = smart             # Only gather facts if not cached
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 7200   # Cache facts for 2 hours
stdout_callback = yaml        # Better readability
callbacks_enabled = timer, profile_tasks

[ssh_connection] pipelining = true # Biggest single speedup ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s

This alone can 3-5x your playbook speed.

See also: 10 Proven Methods to Optimize Ansible Playbook Performance

1. Pipelining (Biggest Single Win)

Without pipelining, every task requires multiple SSH round-trips:

Without pipelining (default):
  SSH → create temp dir → SSH → upload module → SSH → execute → SSH → cleanup
  = 4+ SSH operations per task

With pipelining: SSH → pipe module through stdin → execute = 1 SSH operation per task

[ssh_connection]
pipelining = true

Requirement: Target hosts must NOT have requiretty in sudoers:

# On target, remove/comment this line in /etc/sudoers:
# Defaults    requiretty

Speedup: 2-4x for playbooks with many tasks.

2. Increase Forks

[defaults]
forks = 50    # Default is 5

The forks setting controls how many hosts are processed in parallel. Set it to at least the number of hosts you typically manage.

| Hosts | Recommended Forks | |-------|------------------| | 1-10 | 10 | | 10-50 | 50 | | 50-200 | 100 | | 200+ | 200-500 (depends on controller CPU/RAM) |

Rule of thumb: Each fork uses ~50MB of RAM on the controller.

See also: Ansible Performance Optimization: Speed Up Playbooks for Large-Scale Environments

3. SSH Multiplexing

[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
-C: Compress SSH traffic • ControlMaster=auto: Reuse SSH connections • ControlPersist=60s: Keep connection open for 60 seconds

Speedup: 20-50% fewer SSH handshakes.

4. Fact Caching

[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 7200

Fact gathering takes 2-5 seconds per host. With smart gathering and caching, facts are only gathered on first run.

Redis Caching (Multi-User)

[defaults]
fact_caching = redis
fact_caching_connection = localhost:6379
fact_caching_timeout = 7200

Disable Facts When Not Needed

- hosts: all
  gather_facts: false    # Skip entirely if no facts needed
  tasks:
    - ansible.builtin.ping:

Partial Fact Gathering

- hosts: all
  gather_facts: true
  gather_subset:
    - network           # Only gather network facts
    - '!hardware'       # Skip slow hardware detection
    - '!ohai'
    - '!facter'

See also: Manage Disk Space by Cleaning /var/log/journal on Fedora

5. Free Strategy

Default linear strategy waits for all hosts to complete each task. free lets fast hosts proceed:

- hosts: webservers
  strategy: free
  tasks:
    - name: Install packages
      ansible.builtin.apt:
        name: nginx
        state: present
    # Fast hosts don't wait for slow ones

⚠️ Caveat: Output is interleaved and harder to read. Don't use with serial or when task order across hosts matters.

6. Async Tasks

Run long tasks in the background:

- name: Run long-running update
  ansible.builtin.apt:
    upgrade: dist
  async: 3600      # Max runtime: 1 hour
  poll: 0          # Don't wait — fire and forget

- name: Do other work while update runs ansible.builtin.copy: src: config.conf dest: /etc/myapp/

- name: Wait for update to finish ansible.builtin.async_status: jid: "{{ update_result.ansible_job_id }}" register: job_result until: job_result.finished retries: 60 delay: 30

7. Mitogen Plugin

Mitogen replaces Ansible's SSH/module execution with a faster transport:

pip install mitogen
# ansible.cfg
[defaults]
strategy_plugins = /path/to/mitogen/ansible_mitogen/plugins/strategy
strategy = mitogen_linear

Speedup: 2-7x depending on workload. Biggest gains on playbooks with many small tasks.

⚠️ Compatibility: Doesn't support all connection types. Test thoroughly.

8. Reduce Task Count

Package Lists Instead of Loops

# ❌ SLOW — one SSH round-trip per package
- name: Install packages
  ansible.builtin.apt:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - postgresql
    - redis

# ✅ FAST — single apt transaction - name: Install packages ansible.builtin.apt: name: - nginx - postgresql - redis state: present

Combine Related Tasks

# ❌ SLOW — three separate SSH operations
- ansible.builtin.file:
    path: /opt/app
    state: directory
- ansible.builtin.file:
    path: /opt/app/logs
    state: directory
- ansible.builtin.file:
    path: /opt/app/config
    state: directory

# ✅ FAST — one SSH operation with loop - ansible.builtin.file: path: "{{ item }}" state: directory loop: - /opt/app - /opt/app/logs - /opt/app/config

9. Profile Your Playbooks

[defaults]
callbacks_enabled = timer, profile_tasks, profile_roles
PLAY RECAP ********
Tuesday 13 April 2026  01:00:00 +0000 (0:00:02.345)  0:01:23.456 ****

=============================================================================== Install packages ------------------------------------------ 45.23s Gather facts --------------------------------------------- 12.56s Deploy configuration -------------------------------------- 8.12s Restart services ------------------------------------------ 3.45s

Now you know where to optimize.

10. Limit Scope

# Only run on specific hosts
ansible-playbook site.yml --limit web01,web02

# Only run specific tags ansible-playbook site.yml --tags deploy

# Start at a specific task ansible-playbook site.yml --start-at-task "Deploy application"

Production ansible.cfg

[defaults]
forks = 50
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 7200
stdout_callback = yaml
callbacks_enabled = timer, profile_tasks
host_key_checking = True
retry_files_enabled = False
any_errors_fatal = False

[ssh_connection] pipelining = True ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o ServerAliveInterval=30 control_path_dir = ~/.ansible/cp control_path = %(directory)s/%%h-%%r-%%p

[privilege_escalation] become = True become_method = sudo

Benchmark Results

Typical speedups on a 50-host playbook (20 tasks):

| Optimization | Time | Speedup | |-------------|------|---------| | Default settings | 25 min | 1x | | + Pipelining | 12 min | 2.1x | | + Forks 50 | 5 min | 5x | | + Fact caching | 3.5 min | 7.1x | | + Mitogen | 2 min | 12.5x |

FAQ

What's the single most impactful optimization?

Pipelining. It reduces SSH round-trips from 4+ to 1 per task. Combined with increased forks, you'll see 3-5x speedup immediately.

Will increasing forks overload my controller?

Each fork uses ~50MB RAM. 50 forks = ~2.5GB. Monitor your controller's CPU and RAM. If you hit limits, increase forks gradually and watch for SSH connection errors.

Is Mitogen safe for production?

Mitogen is stable but not officially supported by Red Hat. It works well for most use cases but may have edge cases with certain connection plugins or modules. Test thoroughly in staging first.

Why is gather_facts so slow?

It runs the setup module which collects hardware, network, OS, and package info. Use gather_subset to skip expensive checks (hardware detection is the slowest). Or cache facts and use gathering = smart.

Conclusion

Enable pipelining (2-4x), increase forks to match your host count (2-10x), enable fact caching (skip redundant gathering), and profile your playbooks to find bottlenecks. These four changes alone will make most playbooks 5-10x faster.

Related Articles

Ansible serial Rolling Updates GuideAnsible Check Mode / Dry Run GuideHow to Make Playbooks IdempotentAnsible Inventory Guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home