Ansible has become a cornerstone of modern infrastructure automation, offering a straightforward yet powerful approach to managing IT operations.
From basic package installations to orchestrating complex multi-node deployments, Ansible handles it all.
However, as your automation scales, playbook execution times can become a bottleneck. Implementing the right optimization strategies is essential for maintaining efficient workflows.
This guide explores eight effective methods to dramatically reduce your Ansible playbook execution times.
Table of Contents
1. Diagnose Performance Bottlenecks with Callback Plugins
Before optimizing, you need to identify what’s actually slowing things down. Ansible’s callback plugins provide detailed timing information for every task, helping you pinpoint performance issues.
Enable the timer, profile_tasks, and profile_roles plugins in your configuration:
[defaults]
inventory = ./hosts
callbacks_enabled = timer, profile_tasks, profile_roles
When you run your playbook, you’ll see comprehensive timing data:
===============================================================================
deploy-web-server : Install httpd and firewalld ------- 5.42s
deploy-web-server : Git checkout ---------------------- 3.40s
Gathering Facts --------------------------------------- 1.60s
deploy-web-server : Enable and Run Firewalld ---------- 0.82s
deploy-web-server : firewalld permitt httpd service --- 0.72s
This breakdown reveals exactly where time is being spent, allowing you to focus optimization efforts where they’ll have the greatest impact.
2. Skip Unnecessary Fact Collection
Every Ansible play automatically executes a hidden “Gathering Facts” task that collects system information from target hosts. While useful when you need host details, this step consumes valuable time when you don’t reference these facts in your playbook.
Disable fact gathering by adding gather_facts: false to your play:
See also: Mastering the Linux Command Line — Your Complete Free Training Guide
- name: Deploy Application
hosts: webservers
gather_facts: false
tasks:
- name: Copy configuration file
ansible.builtin.copy:
src: app.conf
dest: /etc/app/app.conf
The time savings multiply with each additional host in your inventory, making this a significant optimization for large-scale deployments.
3. Increase Parallel Execution with Forks
Ansible processes hosts in batches, controlled by the forks parameter. The default value of 5 means Ansible handles only five hosts simultaneously before moving to the next batch.
Boost parallelism by increasing this value in your configuration:
[defaults]
forks = 50
Alternatively, override this at runtime:
ansible-playbook deploy.yml --forks 50
Important consideration: Higher fork values consume more CPU and memory on your control node. Choose a value that balances speed with your system’s available resources.
4. Optimize SSH Connection Handling
SSH connection establishment adds overhead to every task. With numerous tasks and hosts, these connection times accumulate significantly.
Leverage SSH multiplexing to reuse connections:
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
- ControlMaster: Enables multiple SSH sessions to share a single network connection
- ControlPersist: Keeps idle connections open for the specified duration (60 seconds in this example)
This configuration eliminates redundant connection handshakes, substantially reducing overall execution time.
5. Bypass Host Key Verification in Ephemeral Environments
SSH host key verification protects against security threats but adds processing time. In environments where hosts are frequently recreated—such as containerized workloads or auto-scaling infrastructure—host keys change regularly anyway.
For these dynamic environments, consider disabling verification:
[defaults]
host_key_checking = false
Security warning: Only use this setting in controlled, trusted environments. Never disable host key checking in production systems where security is paramount.
6. Enable SSH Pipelining
Standard Ansible execution involves multiple SSH operations for transferring files and executing commands. Pipelining consolidates these operations, reducing the total number of SSH connections required.
Activate pipelining in your configuration:
[ssh_connection]
pipelining = true
Note: Pipelining requires that requiretty is disabled in the sudoers configuration on managed hosts.
7. Implement Alternative Execution Strategies
Ansible’s default linear strategy waits for all hosts to complete a task before proceeding. When tasks are independent, this creates unnecessary delays.
Switch to the free strategy to let hosts progress independently:
- name: Independent Updates
hosts: all_servers
strategy: free
tasks:
- name: Update system packages
ansible.builtin.package:
name: "*"
state: latest
With the free strategy, faster hosts don’t wait for slower ones, reducing total playbook runtime. Consider exploring community strategy plugins like Mitogen for even greater performance gains through optimized Python-based execution.
8. Leverage Asynchronous Task Execution
Long-running tasks like backups, large file transfers, or complex installations can block playbook progression. When subsequent tasks don’t depend on these operations, asynchronous execution prevents unnecessary waiting.
Configure async tasks with appropriate timeout and polling values:
- name: Database Backup Operations
hosts: database_servers
tasks:
- name: Initiate full database backup
ansible.builtin.shell: "/usr/local/bin/db_backup.sh --full"
async: 3600 # Maximum runtime in seconds
poll: 30 # Check status every 30 seconds
- name: Continue with other tasks
ansible.builtin.debug:
msg: "Proceeding while backup runs"
Setting poll: 0 allows the playbook to fire-and-forget, moving immediately to subsequent tasks without waiting for completion.
Continuous Performance Improvement
Optimizing Ansible playbooks is an ongoing process rather than a one-time task. The techniques covered here—callback profiling, fact gathering control, parallelism tuning, SSH optimization, host key management, pipelining, execution strategies, and async tasks—provide a strong foundation for faster automation.
Additional parameters worth exploring include:
- serial: Control batch sizes during rolling updates
- throttle: Limit concurrent task execution within a block
- run_once: Execute tasks on a single host regardless of inventory size
The optimal configuration depends on your specific infrastructure, network conditions, and workload characteristics. Experiment with different combinations to find what works best for your environment, and regularly revisit your settings as your automation needs evolve.



