Lookup vs Query
Last chapter’s wantlist=true was doing important work, but it’s also easy to forget to add. query() is the same lookup plugins, called differently, with that behavior built in automatically.
query(): The Same Lookups, Always Returning A List
msg: "{{ query('fileglob', '*.conf') }}"['app.conf', 'db.conf', 'cache.conf']Same plugin, same pattern, same result as lookup('fileglob', '*.conf', wantlist=true) — just without needing to remember that extra argument at all. query() always returns a genuine list, unconditionally, for any lookup plugin you call through it.
Rewriting The fileglob Example With query()
- name: "Copy config: {{ item }}"
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/app/{{ item | basename }}"
loop: "{{ query('fileglob', 'configs/*.conf') }}"Identical behavior to the previous chapter’s version, one argument shorter. This is the better default going forward for anything feeding straight into loop:.
When Would You Still Use lookup() Instead?
For lookups that naturally produce a single value — file, env, pipe, all from earlier in this section — plain lookup() is still the right call. query() would force even a naturally single-valued result into a one-element list, which then needs awkward [0] indexing to get the actual value back out:
msg: "{{ query('file', 'notes.txt') }}"["file contents here..."]Compare that to lookup('file', 'notes.txt'), which hands back the string directly, with nothing to unwrap. The right tool depends entirely on what shape you actually want: a single value, or a list.
A Note On Multiple Lookup Arguments
Both lookup() and query() accept more than one argument, with every result combined into the final answer:
query('fileglob', '*.conf', '*.yaml')Matches from both patterns, combined into a single list.
Best Practices
- Default to
query()for any lookup that might produce multiple results, especially anything feeding directly intoloop:— it’swantlist=truewith nothing to forget. - Keep plain
lookup()for naturally single-valued lookups (file,env,pipe) — you want the plain value there, not a one-element list needing an index to unwrap. - Remember both accept multiple arguments, combined together into one final result.