AnsibleVI · Configuration and PrecedenceConfiguration and precedence
Which ansible.cfg is actually in effect
What you'll learn
- State the four configuration file locations in search order
- Explain why settings in a lower-priority file have no effect at all rather than partial effect
- Identify the config file in use from ansible --version before troubleshooting anything else
- Predict how changing directory changes which configuration applies
Prerequisites
Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11
An operator raises forks from 5 to 50 in /etc/ansible/ansible.cfg to
speed up a fleet-wide run. The run takes exactly as long as before. They
raise it to 100. No change. They check the file three times; the value is
there.
The setting was never read. A project ansible.cfg existed in the
directory they ran from, and that file was the only configuration Ansible
loaded.
Four locations, in order
Ansible looks in these places and stops at the first one that exists:
| # | Location | Notes |
|---|---|---|
| 1 | $ANSIBLE_CONFIG | A file path, or a directory containing ansible.cfg |
| 2 | ./ansible.cfg | The current working directory only |
| 3 | ~/.ansible.cfg | The invoking user’s home directory |
| 4 | /etc/ansible/ansible.cfg | System-wide |
One sentence carries most of the operational weight:
The first file found is used, and every other file is ignored completely. They do not merge.
Not “the higher-priority file wins where they conflict”. The others are
not consulted at all. A setting that exists only in /etc/ansible/ansible.cfg
has no effect from the moment a project ansible.cfg exists — even if the
project file does not mention that setting.
Prove it. ~/.ansible.cfg sets both forks and timeout:
$ ansible-config dump --only-changedCONFIG_FILE() = /home/ops/.ansible.cfg
DEFAULT_FORKS(/home/ops/.ansible.cfg) = 3
DEFAULT_TIMEOUT(/home/ops/.ansible.cfg) = 60Illustrative output
Now add a project ansible.cfg that sets forks and inventory, and
says nothing about timeout:
$ ansible-config dump --only-changedCONFIG_FILE() = /srv/estate/ansible.cfg
DEFAULT_FORKS(/srv/estate/ansible.cfg) = 30
DEFAULT_HOST_LIST(/srv/estate/ansible.cfg) = ['/srv/estate/inventory']Illustrative output
DEFAULT_TIMEOUT is gone. It has not been overridden by a different
value — it has reverted to the built-in default of 10, because the file
that set it was never opened. Both captures are from ansible-core
2.21.3; the paths have been shortened for the page.
The one command that answers the question
Before diagnosing anything about Ansible behaviour, establish which
configuration is in force. ansible --version reports it on the second
line:
$ ansible --versionansible [core 2.21.3]
config file = /srv/estate/ansible.cfg
configured module search path = ['/home/ops/.ansible/plugins/modules']
ansible python module location = /home/ops/.venvs/estate/lib/python3.12/site-packages/ansible
ansible collection location = /home/ops/.ansible/collections:/usr/share/ansible/collections
executable location = /home/ops/.venvs/estate/bin/ansible
python version = 3.12.7
jinja version = 3.1.4
pyyaml version = 6.0.3 (with libyaml v0.2.5)Illustrative output
When no file is found anywhere, the line is explicit, and this is a real state rather than an error:
ansible [core 2.21.3]
config file = None
Every setting is then at its built-in default: forks 5, timeout 10,
host_key_checking true, inventory /etc/ansible/hosts.
The working directory is part of your configuration
Location 2 is ./ansible.cfg, and . means the current working
directory. There is no search upward through parent directories.
This is worth stating plainly because it contradicts the mental model most
people bring from Git, .editorconfig, tox.ini and every other
project-root file they have used:
/srv/estate/
ansible.cfg <- the project configuration
site.yml
inventory/
playbooks/
patching.yml
Run from /srv/estate, the project config is found. Run from
/srv/estate/playbooks, it is not — Ansible finds nothing in the
current directory and falls through to ~/.ansible.cfg, then to
/etc/ansible/ansible.cfg, then to nothing.
Confirmed on 2.21.3: invoking from a subdirectory of a project that has an
ansible.cfg at its root reported config file pointing at the home
directory file instead.
ANSIBLE_CONFIG accepts a directory
A small convenience with a real use. ANSIBLE_CONFIG may name either a
file or a directory; given a directory, Ansible looks for ansible.cfg
inside it. Verified on 2.21.3.
ANSIBLE_CONFIG=/srv/estate ansible --version
That resolves to /srv/estate/ansible.cfg. It makes wrapper scripts and
CI definitions a little less brittle — they point at the project root,
which is a stable fact, rather than at a filename, which is a
convention.
Knowledge check
Knowledge check · 4 questions
Q1. A project ansible.cfg sets forks = 30 and says nothing about timeout. The user home file ~/.ansible.cfg sets timeout = 60. Running from the project directory, what is the effective timeout?
Q2. Running ansible-playbook from a subdirectory of a project whose ansible.cfg is at the project root still loads that project configuration.
Q3. Which of these are true of ANSIBLE_CONFIG on ansible-core 2.21.3? Select all that apply.
Q4. An engineer raises forks in /etc/ansible/ansible.cfg and the fleet-wide run takes exactly as long as before. What is the first command to run?
Passing score: 75%. Answers are checked in this browser.