Skip to content

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()

copy_configs_query.yaml
- 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 into loop: — it’s wantlist=true with 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.
Last updated on