Optimizing Ansible Execution Speed with the Free Strategy
Learn how to use Ansible's 'free' strategy to eliminate bottlenecks caused by slow hosts and reduce total playbook execution time in large inventories.
19 Sept 2026, 01:16 UTC

The Bottleneck of Linear Execution
By default, Ansible uses the linear strategy: every host in the current batch must finish Task A before any host may begin Task B. If one server in a cluster of fifty hits a network timeout or a slow package mirror, the other forty-nine sit idle, stretching the total deployment window.
The free strategy removes that synchronization. Each managed node works through the play's tasks as fast as its own resources and connectivity allow, without waiting for its peers. For large, heterogeneous inventories where host performance varies, this is the simplest lever for cutting total execution time.
Implementing the Free Strategy
The strategy is set at the play level. Declaring strategy: free stops Ansible from synchronizing task progress across the inventory for that play. You can also enable it globally with strategy = free in the [defaults] section of ansible.cfg, but play-level is safer because it scopes the behavior change. The example below uses fully qualified module names, which require Ansible 2.10 or later; the free strategy itself has been supported throughout the 2.x series.
Configuration Example
Suppose you are installing nginx and deploying its configuration across web servers with mixed hardware — some with fast disks and bandwidth, some without. The tasks are independent per host, which makes this a good fit:
- name: Rapid configuration deployment
hosts: webservers
strategy: free
become: true
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Deploy custom config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
become: true means the connecting user needs sudo privileges on the targets (passwordless sudo, or supply the password with --ask-become-pass). Run the playbook from your control node — the machine with ansible-playbook installed and SSH access to the inventory hosts:
ansible-playbook -i inventory.ini deploy_nginx.yml
Expected result: output is no longer grouped by task. Instead of a TASK [Install nginx] block listing every host, you get an interleaved stream in which a fast server may report nginx already restarted while a slower host is still refreshing its apt cache. Each host still runs the tasks in playbook order; only the cross-host synchronization disappears.
How to check the speedup
To verify the effect on your own inventory, add a diagnostic task that sleeps for a per-host duration — for example, map each host to a different number of seconds via a host variable and run ansible.builtin.command: sleep {{ slow_seconds }}. Run the play twice, once with strategy: free and once with the default. With linear, total runtime stretches to cover the slowest host at every task; with free, fast hosts reach the PLAY RECAP while the slow host is still on its first tasks. Compare the wall-clock time of the two runs.
Critical Limitations and Risks
The free strategy trades cross-host coordination for speed. Several common patterns break or lose their guarantees under it:
- Delegation:
delegate_tostill executes, but timing becomes unpredictable. A task that updates a load balancer after a given host finishes may fire before that host has actually completed its configuration. - Cross-host data: Reading other hosts' values through
hostvarsassumes those hosts have already run the tasks that set them. Underfreethey may not have, so you can read stale or undefined variables. - Coordinated rollouts: Anything that depends on ordering — a database replica waiting for the primary's address, or
serial-based rolling updates where you must know exactly which hosts are offline — loses its guarantees.
If a play depends on any of these, keep it on linear and reserve free for plays whose tasks are genuinely independent, such as package installation or configuration file deployment.
Log readability
Because hosts finish tasks out of sequence, console output interleaves and is harder to audit. For production runs, write per-host logs with a callback plugin such as community.general.log_plays, or execute through AWX or Ansible Automation Platform, which records results per host so a single host's timeline can be reconstructed.
Linear vs. Free at a Glance
| Aspect | Linear (default) | Free |
|---|---|---|
| Execution flow | Lock-step, task by task | Independent per host |
| Total runtime | Bound by the slowest host at every task | Bound by the slowest host's full path |
| Cross-host coordination | Predictable ordering | Not guaranteed |
| Console output | Grouped by task | Interleaved by host |
Reverting the Change
Switching strategies does not change the state of managed nodes — it only changes the order in which Ansible sends tasks, so there is nothing to roll back on the infrastructure. To return to synchronized execution, delete the strategy: free line (or set it back to linear) and re-run the playbook.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.