Skip to main content
RunBook Academy

AnsibleXXX · Host Targeting and Blast RadiusNarrowing a run

--limit and limit files

Intermediate⏱ ~26 minbash

What you'll learn

  • Predict the effective host list from a play hosts: line and a --limit together
  • Use --limit for a single host, a canary group, a region and a wave
  • Write and consume a limit file, including comments, groups and operators
  • Recognise the two zero-host outcomes of --limit and which one is silent

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

Not yet marked complete on this device.

--limit is the most-used safety control in Ansible, and it is misunderstood in one specific way that matters.

--limit intersects with the play’s hosts: line. It does not replace it.

The effective host list is the intersection of the two. A --limit can only ever make a play target fewer hosts than its hosts: line already selects — never more, never different.

That is a strong guarantee and it is the reason --limit is the right habitual way to narrow a run. It is also why a --limit naming a host the play never targeted quietly does nothing.

The intersection, demonstrated

Every example uses one playbook whose single play is hosts: web, against the ten-host inventory from lesson 2.

Read-only / Safeno limit - the play's own pattern
$ ansible-playbook -i inventory/hosts.yml site.yml --list-hosts
playbook: site.yml

play #1 (web): Configure the web tier	TAGS: []
  pattern: ['web']
  hosts (4):
    web01.example.com
    web02.example.com
    web03.example.com
    web04.example.com
Read-only / Safe--limit narrows to one host
$ ansible-playbook -i inventory/hosts.yml site.yml --limit web01.example.com --list-hosts
  play #1 (web): Configure the web tier	TAGS: []
  pattern: ['web']
  hosts (1):
    web01.example.com
Read-only / Safe--limit all does not widen anything
$ ansible-playbook -i inventory/hosts.yml site.yml --limit all --list-hosts
  play #1 (web): Configure the web tier	TAGS: []
  pattern: ['web']
  hosts (4):
    web04.example.com
    web02.example.com
    web03.example.com
    web01.example.com

That third case is the guarantee in action. There is no --limit value that reaches a host the play was not already going to reach.

The four shapes you will actually use

Configuration changesingle host - the smallest possible change
ansible-playbook -i inventory/ site.yml --limit web01.example.com --check --diff
Configuration changecanary group - a named set that survives inventory changes
ansible-playbook -i inventory/ site.yml --limit canary
Configuration changeregion or environment - a blast-radius boundary that already exists
ansible-playbook -i inventory/ site.yml --limit eu_west
Configuration changea wave - the remainder after the canary
ansible-playbook -i inventory/ site.yml --limit 'us_east:!canary'

-l is the short form and works identically on ansible, ansible-playbook and ansible-inventory:

Read-only / Safethe same limit on three commands
$ ansible -i inventory/hosts.yml web -l canary --list-hosts
  hosts (1):
  web01.example.com

Limit files

--limit @file reads the pattern from a file. This is the form that turns a host list into a reviewable artefact.

Read-only / Safechange-ops-5512.limit
# change ticket OPS-5512 - approved 2026-08-11 by the platform team
# generated from: ansible -i inventory/ 'web:&eu_west' --list-hosts
web01.example.com

web03.example.com
Read-only / Safethe file drives the run
$ ansible-playbook -i inventory/hosts.yml site.yml --limit @change-ops-5512.limit --list-hosts
  play #1 (web): Configure the web tier	TAGS: []
  pattern: ['web']
  hosts (2):
    web03.example.com
    web01.example.com

Operators are allowed in a limit file too, which is occasionally what you want and more often a sign the file should have been a plain list:

Read-only / Safea limit file containing a group and an exclusion
$ ansible-playbook -i inventory/hosts.yml site.yml --limit @wave2.limit --list-hosts
  play #1 (web): Configure the web tier	TAGS: []
  pattern: ['web']
  hosts (3):
    web04.example.com
    web03.example.com
    web02.example.com

A missing limit file is a hard error rather than an empty limit, which is the correct behaviour and worth knowing:

Read-only / Safethe file is not there
$ ansible-playbook -i inventory/hosts.yml site.yml --limit @typo.limit --list-hosts
[ERROR]: Unable to find limit file b'/path/to/typo.limit'

The workflow this enables

  1. Resolve the intended target and capture it: ansible -i inventory/ "<pattern>" --list-hosts | tail -n +2 | tr -d " " > change-OPS-5512.limit
  2. Add a header comment naming the ticket, the date, and the pattern the list came from, so the file explains itself six months later.
  3. Attach the file to the change record. It is the answer to "which hosts" in a form a reviewer can count and disagree with.
  4. Run against the file rather than the pattern: --limit @change-OPS-5512.limit. The list was frozen at review time, so a host created since then is not in it.
  5. Keep the file with the change record. After an incident it is the only artefact that says what the run was meant to touch, as distinct from what it did touch.

Step four is the one that matters for a dynamic inventory. A pattern re-resolves at execution time and can produce a different answer from the one that was reviewed; a limit file cannot. That is the closest a dynamic estate gets to the property a static inventory has for free.

Knowledge check

Knowledge check · 4 questions

  1. Q1. A play has hosts: web, which resolves to four hosts. The inventory has ten hosts. What does --limit all produce?

  2. Q2. An operator runs the web playbook with --limit db01.example.com, where db01 exists in the inventory. What happens?

  3. Q3. Which are true of a limit file passed as --limit @file? Select all that apply.

  4. Q4. Passing --limit twice on one command line applies only the second one.

Passing score: 75%. Answers are checked in this browser.