Ansible with_items vs loop: Migration Guide & Key Differences (2026)
By Luca Berton · Published 2024-01-01 · Category: installation
Complete guide to Ansible with_items vs loop. Understand the differences, migrate from with_* to loop, use loop_control, and handle complex iteration patterns with practical examples.
Ansible has two ways to iterate over data: the modern loop keyword (introduced in Ansible 2.5) and the legacy with_ keywords (with_items, with_dict, with_fileglob, etc.). This guide explains the differences, when to use each, and how to migrate.
Quick Comparison
Both produce identical results. The difference is in how they handle complex data.
Key Differences
| Feature | with_items | loop | |---------|-------------|--------| | Introduced | Ansible 1.x | Ansible 2.5 | | Auto-flattening | ✅ Yes (1 level) | ❌ No | | Syntax | with_items: list | loop: list | | Complex iteration | with_dict, with_nested, etc. | loop + filters | | Deprecation | Soft-deprecated (still works) | Recommended | | Performance | Same | Same |
with_items Auto-Flattening
The biggest behavioral difference — with_items automatically flattens one level of nested lists:
Migration: with_ to loop
with_items → loop
with_list → loop (identical)
with_dict → loop + dict2items
with_nested → loop + product
with_subelements → loop + subelements
with_sequence → loop + range
with_fileglob → loop + fileglob lookup
with_together → loop + zip
loop_control
The loop keyword works with loop_control for advanced iteration control:
Extended Loop Variables
With extended: true:
| Variable | Description | |----------|-------------| | ansible_loop.index | Current iteration (1-based) | | ansible_loop.index0 | Current iteration (0-based) | | ansible_loop.first | true on first iteration | | ansible_loop.last | true on last iteration | | ansible_loop.length | Total number of items | | ansible_loop.revindex | Iterations remaining (1-based) | | ansible_loop.previtem | Previous item | | ansible_loop.nextitem | Next item |
When to Use with_items vs loop
Use loop (recommended): • All new playbooks • Simple list iteration • When you need loop_control • When you want explicit behavior (no auto-flattening)
Use with_ (acceptable): • Legacy playbooks that work correctly • with_fileglob (simpler than lookup('fileglob', ..., wantlist=True)) • When the filter-based equivalent is significantly more complex • Maintaining consistency in an existing codebase
Is with_items Deprecated?
with_items and other with_ keywords are not officially deprecated as of Ansible 2.17/ansible-core 2.17. They are considered legacy and the documentation recommends loop, but they still work and will continue to work for the foreseeable future.
The ansible-lint tool flags with_ usage as a warning (rule no-jinja-when) but not as an error.
FAQ
What is the difference between with_items and loop in Ansible?
The main difference is auto-flattening: with_items automatically flattens one level of nested lists, while loop passes data as-is. For simple lists, they behave identically. loop is the modern recommended syntax and supports loop_control for advanced features.
Is with_items deprecated in Ansible?
No, with_items is not officially deprecated and still works in all current Ansible versions. However, it's considered legacy syntax. The Ansible documentation recommends using loop for new playbooks, and ansible-lint may flag with_ usage as a style warning.
How do I convert with_items to loop?
For simple lists, replace with_items directly with loop. If your data has nested lists and you relied on auto-flattening, add | flatten: loop: "{{ my_list | flatten }}". For with_dict, use loop: "{{ my_dict | dict2items }}".
Can I use loop_control with with_items?
No, loop_control only works with the loop keyword. This is one of the main reasons to migrate from with_items to loop — you gain access to label, index_var, pause, extended, and loop_var.
Which is faster, with_items or loop?
Performance is identical. Both iterate in the same way internally. The choice should be based on clarity and features, not performance.
Conclusion
For all new Ansible playbooks, use loop: • loop — Modern, explicit, supports loop_control • with_items — Legacy, auto-flattens, still works • Migration: Usually just rename with_items to loop; add | flatten if you relied on auto-flattening • with_dict → loop + dict2items; with_nested → loop + product
The filter-based approach with loop is more explicit and composable, making your playbooks easier to understand and maintain.
Related Articles • Ansible loop_control: label, index_var, pause & loop_var Guide • Ansible Flatten: Nested Lists in Playbooks • Ansible map Filter: Extract Attributes from Lists • Ansible dict2items: Convert Dictionaries to Lists
Category: installation