Introduction
One key component of Ansible is its inventory. Ansible’s inventory lets you organise and define the targets you will automate. Whether you're automating a small network or a large-scale deployment, a solid inventory setup—and knowing how to work with it—makes all the difference.
In this post, we’ll explore the two types of Ansible inventory—static and dynamic—and their role in network automation. We will also examine the different inventory formats (INI and YAML), learn how to configure dynamic inventories using plugins for Sources of Truth such as NetBox, and discover how to filter your inventory for greater control over which host you are automating!
Let's go!
What is an Ansible Inventory?
An Ansible inventory is a collection of hosts and the necessary data to allow Ansible to connect to them. In other words, it defines the "who"!
For example, an inventory includes IP addresses, authentication credentials, and other configuration details needed for Ansible to execute tasks on the target systems. This information enables Ansible to interact with the correct devices and apply the desired automation defined in a Playbook.
Below is a high-level overview of the Ansible inventory.

Types of Ansible Inventory
Ansible supports two primary types of inventory: Static and Dynamic.
Static Inventory
A static inventory is a manually maintained file that lists all hosts and their groupings. Typically written in INI or YAML format, a static inventory is ideal for environments where host configurations are stable and require infrequent modifications.
Dynamic Inventory
A dynamic inventory retrieves host and group information at runtime from external systems such as a Source of Truth like NetBox, configuration management databases, or APIs. By leveraging scripts or plugins, dynamic inventories automatically generate an up-to-date list of the required inventory information for Ansible to successfully execute tasks on the target systems. This makes them well-suited for large-scale, dynamic environments where inventory data needs to reflect frequent changes.
Comparison: Static vs. Dynamic Inventory
Feature | Static Inventory | Dynamic Inventory |
Setup | Manually created and maintained | Uses scripts or plugins to fetch hosts dynamically |
Updates | Requires manual updates | Automatically updates as infrastructure changes |
Use Case | Small, stable environments | Large, dynamic environments or those leveraging a Source of Truth like NetBox |
Scalability | Limited scalability | Highly scalable |
Examples | Flat files in INI or YAML format | NetBox, InfraHub plugins. |
Inventory Formats in Ansible
Ansible supports static inventories defined in either INI or YAML-based formats. Below are examples of both formats:
Static Inventory – INI Format
The INI format is straightforward and easy to use. Hosts and groups are organized using sections defined by square brackets ([]
). A basic example of an INI inventory for managing network devices might look like this:
# Inventory file for managing network devices
# Group: Core Routers
[core_routers]
router1 ansible_host=192.168.0.1 ansible_network_os=ios
router2 ansible_host=192.168.0.2 ansible_network_os=ios
# Group: Access Switches
[access_switches]
switch1 ansible_host=192.168.1.1 ansible_network_os=nxos
switch2 ansible_host=192.168.1.2 ansible_network_os=nxos
# Group: Firewalls
[firewalls]
fw1 ansible_host=192.168.2.1 ansible_network_os=asa
fw2 ansible_host=192.168.2.2 ansible_network_os=asa
# Nested Group: All Network Devices
[network_devices:children]
core_routers
access_switches
firewalls
# Group Variables for Switches
[access_switches:vars]
vlans=10,20,30
In this example, the [network_devices:children]
section groups together the core_routers
, access_switches
, and firewalls
groups. This logical grouping allows you to apply tasks to all network devices at once, while still enabling targeted actions on individual groups when necessary.
Static Inventory – YAML Format
YAML provides a structured way to define inventories, making them easier to manage and validate. Its format allows for linting tools to check for syntax errors, which is especially useful in CI/CD pipelines.
Below is an example of how the same inventory can be represented in YAML:
all:
children:
core_routers:
hosts:
router1:
ansible_host: 192.168.0.1
ansible_network_os: ios
router2:
ansible_host: 192.168.0.2
ansible_network_os: ios
access_switches:
hosts:
switch1:
ansible_host: 192.168.1.1
ansible_network_os: nxos
switch2:
ansible_host: 192.168.1.2
ansible_network_os: nxos
vars:
vlans: [10, 20, 30]
firewalls:
hosts:
fw1:
ansible_host: 192.168.2.1
ansible_network_os: asa
fw2:
ansible_host: 192.168.2.2
ansible_network_os: asa
network_devices:
children:
- core_routers
- access_switches
- firewalls
Dynamic Inventory: NetBox Integration Example
NetBox is a widely adopted source of truth for network devices. The dynamic inventory plugin integrates NetBox with Ansible, allowing you to automatically pull device details into Ansible and use those hosts as your targets.
stalling and Setting Up the NetBox Ansible Collection
To setup NetBox as your dynamic inventory source, you will need to:
- Install the NetBox Ansible Collection
This will contain the NetBox inventory plugin.
ansible-galaxy collection install netbox.netbox
- Set Environment Variables
Configure your shell with the necessary environment variables to securely store your NetBox API details.
export NETBOX_API="https://netbox.example.com"
export NETBOX_TOKEN="YOUR_NETBOX_API_TOKEN"
- Create a YAML Configuration File
Create a configuration file (e.g.,nb_inventory.yaml
) with the required parameters to enable the NetBox plugin.
Example Configuration
Save the following content in nb_inventory.yaml
:
plugin: ansible.netcommon.netbox
api_endpoint: "https://netbox.example.com"
token: "YOUR_NETBOX_API_TOKEN"
validate_certs: False
query_filters:
site: HQ
group_by:
- device_role
- device_type
Example Configuration
Below is a sample configuration snippet that demonstrates how to integrate NetBox as a dynamic inventory source in Ansible:
Add the following into nb_invenrtory.yaml
:
# API token is dynamically retrieved from the environment variable
token: "{{ lookup('env','NETBOX_TOKEN') }}"
# Enforce SSL certificate validation
validate_certs: True
# Incorporate NetBox configuration contexts into host variables
config_context: True
# Group devices by their roles
group_by:
- device_roles
# Remove any prefixes from group names for clarity
group_names_raw: True
# Compose custom variables from NetBox data (e.g., network OS)
compose:
ansible_network_os: "platform.name"
# Filter devices: include only those with a primary IP and matching tenant
query_filters:
- has_primary_ip: True
- tenant: "TenantA"
Key Configuration Parameters
token
:
The API token used for authentication is sourced from environment variables loaded within the shell.validate_certs
:
A boolean value that determines whether SSL certificates are validated when connecting to NetBox. Setting this toTrue
ensures secure communication. If using self-signed certificates, you will need to set it toFalse
.config_context
:
Enables the inclusion of NetBox configuration contexts into Ansible host variables.group_by
:
Defines how devices are organized in the inventory. In this example, devices are grouped by theirdevice_roles
.group_names_raw
:
Strips prefixes from group names, resulting in cleaner and more readable group identifiers.compose
:
Allows you to create custom variables from NetBox attributes. In this example,ansible_network_os
is derived from the device'splatform.name
attribute within NetBox.query_filters
:
Filters that allow narrowing down the devices retrieved from NetBox. The filters in this example ensure that only devices with a primary IP address (has_primary_ip: True
) and belonging toTenantA
are included in the inventory.
Running the Dynamic Inventory
Once the configuration file (nb_inventory.yaml
) is created, you can run the dynamic inventory with the following commands:
- View the Inventory Structure as a Graph:
ansible-inventory -i nb_inventory.yaml --graph
- Run an Ansible Playbook Using the NetBox Inventory:
ansible-playbook -i nb_inventory.yaml playbook.yaml
Ansible Inventory Command-Line Tool
The ansible-inventory
command-line tool provides insight into Ansible inventories. By default, it outputs inventory data in JSON format.
These tools are extremely useful when using a dynamic inventory to ensure that your plugin and configuration are working as expected.
Common Options
ansible-inventory --graph
Creates an inventory graph. If supplying a pattern, it must be a valid group name. This command ignores the limit option.
This command displays the inventory as a tree structure, making it useful for understanding hierarchical relationships among groups and hosts. It provides a high-level overview, making it easier to read than --list
.
Example Output:
@all:
|--@core_routers:
| |--router1
| |--router2
|--@access_switches:
| |--switch1
| |--switch2
|--@firewalls:
| |--fw1
| |--fw2
|--@network_devices:
|--@core_routers:
| |--router1
| |--router2
|--@access_switches:
| |--switch1
| |--switch2
|--@firewalls:
|--fw1
|--fw2
ansible-inventory --list
Outputs all host and group information in JSON format.. This command is useful for debugging and understanding inventory structure, along with the data that has been pulled from the dynamic inventory source.
It displays all hosts and their group memberships and variables associated with hosts and groups.
Example Output:
{
"all": {
"children": {
"core_routers": {
"hosts": {
"router1": {
"ansible_host": "192.168.0.1",
"ansible_network_os": "ios"
},
"router2": {
"ansible_host": "192.168.0.2",
"ansible_network_os": "ios"
}
}
},
"access_switches": {
"hosts": {
"switch1": {
"ansible_host": "192.168.1.1",
"ansible_network_os": "nxos"
},
"switch2": {
"ansible_host": "192.168.1.2",
"ansible_network_os": "nxos"
}
},
"vars": {
"vlans": [
10,
20,
30
]
}
},
"firewalls": {
"hosts": {
"fw1": {
"ansible_host": "192.168.2.1",
"ansible_network_os": "asa"
},
"fw2": {
"ansible_host": "192.168.2.2",
"ansible_network_os": "asa"
}
}
},
"network_devices": {
"children": [
"core_routers",
"access_switches",
"firewalls"
]
}
}
}
}
Comparison: --list vs --graph
Feature | --list |
--graph |
---|---|---|
Output Format | JSON | Tree Structure |
Detail Level | Detailed, includes host variables | Simplified, focuses on hierarchy |
Use Case | Debugging, variable inspection | Quick group-host relationship view |
Human-Readability | Moderate (requires JSON parsing) | High (easy to read at a glance) |
Filtering Ansible Playbook Execution with --limit
The --limit
option in Ansible is used to restrict execution to specific hosts or groups, whether running ansible-inventory
or ansible-playbook
.
- Using
--limit
withansible-playbook
When running an Ansible playbook, you can limit the execution to specific hosts or groups by adding the--limit
flag.
Basic Syntax:
ansible-playbook -i inventory.yaml playbook.yaml --limit <target>
Where <target>
can be:
- A single host (e.g.,
router1
) - A group (e.g.,
access_switches
) - Multiple hosts or groups (using
:
separator) - Exclusions (
!
operator) - Wildcards (
*
for pattern matching)
Here’s a table summarizing various ways to use the --limit
option with ansible-playbook
:
Use Case | Command Example | Description |
---|---|---|
Limit to a specific host | ansible-playbook -i inventory.yaml playbook.yaml --limit router1 |
Runs the playbook only on router1 . |
Limit to a specific group | ansible-playbook -i inventory.yaml playbook.yaml --limit access_switches |
Runs the playbook only on the access_switches group. |
Limit to multiple hosts | ansible-playbook -i inventory.yaml playbook.yaml --limit "router1:fw1" |
Runs the playbook on router1 and fw1 . |
Limit to multiple groups | ansible-playbook -i inventory.yaml playbook.yaml --limit "core_routers:firewalls" |
Runs the playbook on both core_routers and firewalls groups. |
Exclude a group | ansible-playbook -i inventory.yaml playbook.yaml --limit "!firewalls" |
Runs the playbook on all hosts except those in firewalls group. |
Exclude a specific host | ansible-playbook -i inventory.yaml playbook.yaml --limit "!router1" |
Runs the playbook on all hosts except router1 . |
Use wildcard to match hosts | ansible-playbook -i inventory.yaml playbook.yaml --limit "router*" |
Runs the playbook on all hosts with names starting with router . |
Use a combination of include & exclude | ansible-playbook -i inventory.yaml playbook.yaml --limit "access_switches:!switch2" |
Runs the playbook on access_switches group but excludes switch2 . |
Using hosts within Playbook
While the --limit
option filters hosts at runtime, the hosts
keyword inside the playbook defines the target hosts.
Example Playbook (playbook.yaml
):
- name: Configure Network Devices
hosts: core_routers
gather_facts: no
tasks:
- name: Ping the devices
...
If you run the following command, the playbook runs on all hosts in the core_routers
group due to the hosts
keyword being devices within the Play.
ansible-playbook -i inventory.yaml playbook.yaml
Closing Comments
We hope you enjoyed this post! The Ansible Inventory is a key feature that any Ansible automator must understand. We've explored how static and dynamic inventories work, how they simplify host management, and how CLI tools like ansible-inventory help troubleshoot, especially when using dynamic-based inventories.