Ansible Inventory Patterns — Target Hosts and Groups

Introduction

Inventory patterns control which hosts Ansible targets. Instead of running against all hosts, you can target specific groups, use wildcards, combine groups with AND/OR/NOT logic, and use regex — all from the command line or in playbooks.

Basic Patterns

# All hosts
ansible all -m ping

# Specific group
ansible webservers -m ping

# Specific host
ansible db01 -m ping

# Multiple groups
ansible 'webservers:databases' -m ping

# Multiple hosts
ansible 'web01:web02:db01' -m ping

Wildcard Patterns

# All hosts starting with "web"
ansible 'web*' -m ping

# All .example.com hosts
ansible '*.example.com' -m ping

# Single character wildcard
ansible 'web0?' -m ping  # web01, web02, ... web09

Group Operations

Union (OR) — hosts in either group

ansible 'webservers:databases' -m ping

Intersection (AND) — hosts in BOTH groups

ansible 'webservers:&production' -m ping
# Only hosts that are in webservers AND production

Exclusion (NOT) — hosts NOT in a group

ansible 'webservers:!staging' -m ping
# Webservers that are NOT in staging

Complex Patterns

# Production webservers, excluding hosts being patched
ansible 'webservers:&production:!patching' -m ping

# All hosts in either web or db, but only in production
ansible 'webservers:databases:&production' -m ping

Regex Patterns

# Regex (prefix with ~)
ansible '~web[0-9]+\.example\.com' -m ping

# Match numbered hosts
ansible '~^(web|db)[0-9]{2}$' -m ping

Numeric Ranges

# inventory.yml — range shorthand
all:
  children:
    webservers:
      hosts:
        web[01:50]:           # web01 through web50
        web[a:f]:             # weba through webf
    databases:
      hosts:
        db-[01:03]:           # db-01, db-02, db-03
    caches:
      hosts:
        192.168.1.[10:20]:    # IP range

Playbook Targeting

# Target specific groups in playbooks
---
- name: Configure all web servers
  hosts: webservers
  tasks: [...]

- name: Configure production databases only
  hosts: databases:&production
  tasks: [...]

- name: All servers except staging
  hosts: all:!staging
  tasks: [...]

# Dynamic host targeting
- name: Target from variable
  hosts: "{{ target_hosts | default('all') }}"
  tasks: [...]
# Override at runtime
ansible-playbook site.yml -e "target_hosts=web01"

--limit Flag

Restrict targets at runtime without editing playbooks:

# Limit to one host
ansible-playbook site.yml --limit web01

# Limit to multiple hosts
ansible-playbook site.yml --limit 'web01,web02'

# Limit with pattern
ansible-playbook site.yml --limit 'web*'

# Limit to group intersection
ansible-playbook site.yml --limit 'webservers:&production'

# Exclude hosts
ansible-playbook site.yml --limit 'all:!db01'

# Retry failed hosts from last run
ansible-playbook site.yml --limit @site.retry

Inventory Listing

# Show all hosts in inventory
ansible-inventory --list

# Show hosts matching a pattern
ansible-inventory --host web01

# Graph view
ansible-inventory --graph

# Graph of specific group
ansible-inventory --graph webservers

Output:

@all:
  |--@webservers:
  |  |--web01
  |  |--web02
  |--@databases:
  |  |--db01
  |--@ungrouped:
  |  |--monitoring01

Special Groups

GroupContains
allEvery host in inventory
ungroupedHosts not in any group (except all)
localhostThe control machine
# Target localhost explicitly
- hosts: localhost
  connection: local
  tasks:
    - name: Run locally
      ansible.builtin.debug:
        msg: "Running on controller"

Nested Groups

# inventory.yml
all:
  children:
    production:
      children:
        prod_web:
          hosts:
            web01:
            web02:
        prod_db:
          hosts:
            db01:
    staging:
      children:
        stag_web:
          hosts:
            stag-web01:
        stag_db:
          hosts:
            stag-db01:
# Target all production (web + db)
ansible production -m ping

# Target only production web servers
ansible prod_web -m ping

Troubleshooting

IssueSolution
"No hosts matched"Check pattern syntax and inventory: ansible-inventory --list
Wrong hosts selectedUse --list-hosts to preview: ansible-playbook site.yml --list-hosts
Host in wrong groupCheck inventory structure: ansible-inventory --graph
Pattern not workingQuote patterns with special chars: ansible 'web*:&prod' -m ping

Best Practices

  1. Use semantic group names — webservers, databases, not group1
  2. Nest groups for environments — production > prod_web, staging > stag_web
  3. Use --limit for one-offs — don't edit inventory for temporary restrictions
  4. Test with --list-hosts — preview targeting before running
  5. Avoid all in production — be explicit about which hosts you target

Conclusion

Inventory patterns give you surgical precision in host targeting. Master union (:), intersection (&), and exclusion (!) operators, and you can target any combination of hosts without modifying your inventory or playbooks.