Ansible is an incredibly powerful automation and configuration management tool used by admins and developers alike. One of its most useful features is the with_items lookup plugin, which allows you to easily iterate over lists to configure infrastructure in bulk.
In this comprehensive guide, we’ll cover how Ansible looping with with_items works under the hood, why it should be preferred over repetitive tasks, and how to utilize it effectively in your playbooks.
What is Ansible with_items?
The with_items construct in Ansible allows you to repeat a task over a list provided to it, substituting each value of the list in and running the task sequentially.
This saves you from needing to manually repeat tasks and lines up perfectly with Ansible’s idempotence capabilities.
Here is a quick example:
- name: Add several users
user:
name: "{{ item }}"
groups: wheel
with_items:
- testuser1
- testuser2
Instead of adding the user resource twice explicitly, we let Ansible handle the looping so our playbook configuration stays clean and readable.
How Ansible with_items Works
When Ansible comes across the with_items syntax, it takes the list variable provided and goes through the following process:
- Take first item in list
- Substitute
{{ item }}with list item‘s value - Execute the task using substituted value
- Check if fail/errors occurred
- Move to next item in list
- Repeat steps 2-5 until list is exhausted
By following this procedure, you get the power of looping without explicit coding. Ansible handles all the internals – allowing you to focus on infrastructure configuration alone.
A few notable capabilities provided by with_items:
- Works with all Ansible modules for maximum flexibility
- Allows lists with elements of any data types
- Supports 1 level of nested lists
- Inline conditional logic with
whenstatements - Access loop metadata like
item_index
These features unlock extremely powerful Ansible patterns as you’ll see through examples later.
Why Choose Ansible with_items Over Explicit Repetition
While it is possible to simply repeat tasks instead of using with_items, doing so has major downsides:
Hurts Playbook Readability
Copying a task multiple times makes the playbook messy and harder to parse visually. with_items keeps things clean through looping abstraction.
More Prone to Errors
Updating a single parameter would require updating it in multiple places with copy/pasted tasks. With a loop any fixes apply across all iterations.
Performance Hits
Running the same task inline multiple times adds overhead compared to with_items, as you can see in the benchmark data below:

As the chart demonstrates, with_items is 16-32% faster than the explicit repeated task. By optimizing the looping internals, Ansible makes bulk actions extremely efficient.
For all these reasons, leaning on with_items for any repeated actions makes total sense!
Ansible with_items By Example
Now that you understand the basics of with_items, let‘s walk through some practical examples of how it can be applied in playbooks.
We‘ll explore simple use cases first then build up to more advanced configurations leveraging hash data.
Installing Multiple Packages
- name: Install required packages
apt:
name: "{{ item }}"
state: latest
with_items:
- nginx
- php
- php-mysql
By switching to with_items, we turn a 12 line playbook into just 5 without losing anything!
Creating User Accounts
- name: Add initial user accounts
user:
name: "{{ item.name }}"
group: "{{ item.group }}"
with_items:
- { name: ‘john‘, group: ‘sudo‘ }
- { name: ‘jane‘, group: ‘admin‘ }
Here we create user accounts from a list of hashes allowing full configurability of each account.
Configuring Monitoring Checks
- name: Setup service monitoring
uri:
url: "https://monitor.com/api/{{ item.type }}"
method: POST
body: "{{ item.config }}"
register: result
ignore_errors: true
with_items:
- { type: smtp, config: "{/* smtp config */}" }
- { type: http, config: "{/* http config */}" }
This demonstrates running API commands against a monitoring system utilizing with_items to iterate over hashes containing the unique parameters per check.
Best Practices for Ansible with_items
Follow these guidelines when working with with_items to create clean and failure-resistant playbooks:
Use Descriptive Task Names
Give each looped task a name that communicates what is being done, like "Install Apache Modules" or "Add Monitoring Checks"
Structure Lists for Readability
Format list data cleanly and logically such that it is easy to parse. For hashes, consider one hash per line with consistent indentations.
Fail Safely with ignore_errors
Looping over items means errors impacting just some values may not warrant total failure. ignore_errors: true prevents full task failure if desired.
Leverage item_index for Advanced Logic
When you need to do something unique on certain iterations, the item_index magic variable contains the 0-based index value usable in conditional statements.
Adhering to these best practices will lead to smooth experience with with_items in your playbooks!
Conclusion
Ansible‘s built-in with_items lookup sets it apart from other configuration management tools. By enabling simple yet powerful looping, Ansible allows you to remove tons of playbook repetition and focus purely on infrastructure state.
Key takeaways include:
- Substitute
{{ item }}values from provided list - Supports all modules and data types
- far faster than explicit repetition
- Readable abstraction over messy copy/paste
- Advanced capabilities via list hashes
Learning to leverage with_items will level up your ability to elegantly configure systems at scale with Ansible. The loops construct perfectly complements the Ansible mindset – simplify and automate all the things!
Have you found clever uses for Ansible‘s with_items in your infrastructure environment? Share your experiences and best practices below!


