# When should modules use/return \`ansible\_facts\`?

**URL:** <https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297>\
**Category:** Collection Development\
**Tags:** dev, module, facts, community-wg\
**Created:** [February 16, 2025, 3:20pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297 "2025-02-16T15:20:03Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [February 16, 2025, 3:20pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/1 "2025-02-16T15:20:04Z")

</div>

Modules can return regular return values as well as `ansible_facts`, which automatically appear in the global namespace ([unless you set `INJECT_FACTS_AS_VARS=false`](https://docs.ansible.com/ansible/devel/reference_appendices/config.html#inject-facts-as-vars) - though doing that will likely break a lot of playbooks and roles). Most modules returning `ansible_facts` have the suffix `_facts` in the module name, though there are exceptions (for example [`ansible.builtin.hostname`](https://docs.ansible.com/ansible/devel/collections/ansible/builtin/hostname_module.html), which [updates several hostname-related facts](https://github.com/ansible/ansible/blob/478806e668ec5df9b2d4971cc3c4e8425b33867d/lib/ansible/modules/hostname.py#L895-L898)).

Right now the only guidance we give on whether a module should return `ansible_facts` is here: [Developing modules — Ansible Community Documentation](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_general.html#creating-an-info-or-a-facts-module)

> Only use `ansible_facts` for information that is specific to the host machine, for example network interfaces and their configuration, which operating system and which programs are installed.

I want to start a discussion to elaborate on that, and I would even suggest to limit the use of `ansible_facts` even further, and basically dissuade its use unless some very explicit exceptions.

The reason I want to start this discussion now is that there’s a new [PR in community.general for adding a systemd\_facts module](https://github.com/ansible-collections/community.general/pull/9750), which I personally think should be an `_info` module since the returned values aren’t “proper” facts: first you can limit the set of systemd units you want infos on, and second you can specify additional properties to query. Therefore the facts the module returns depend not only on the system (and on the time of querying), but also on the module settings.

Obviously all facts modules somehow depend on the time of invocation - if you list the disks in a system, someone might have pulled one out or put a new one in by the time your role/playbook uses the fact. (Plug and play, yay!) The same is true for [mount facts (`ansible.builtin.mount_facts`)](https://docs.ansible.com/ansible/devel/collections/ansible/builtin/mount_facts_module.html) - a task inbetween might have mounted, remounted, or unmounted something - and [package facts (`ansible.builtin.package_facts`)](https://docs.ansible.com/ansible/devel/collections/ansible/builtin/package_facts_module.html) - a task inbetween might have installed, upgraded, or removed a package. Also the facts output of modules like `ansible.builtin.mount_facts` depends on module options.

I’m still not sure what to think about facts like installed packages, mounts, and services, but generally I would say anything where facts retrieval can be configured (so that the values of the facts depend on these options) should very likely **not** facts, but `_info` modules. community.general has its share of examples:

- [`community.general.listen_port_facts`](https://docs.ansible.com/ansible/devel/collections/community/general/listen_ports_facts_module.html): depending on the program used and the option `include_non_listening` you get different results.
- [`community.general.snmp_facts`](https://docs.ansible.com/ansible/devel/collections/community/general/snmp_facts_module.html): these are actually queried for another host, not for the machine the module runs on!
- [`community.general.zfs_facts`](https://docs.ansible.com/ansible/devel/collections/community/general/zfs_facts_module.html): you can select the ZFS dataset, which properties to query, etc. This will be returned under the global name `ansible_zfs_datasets`.
- [`community.general.zpool_facts`](https://docs.ansible.com/ansible/devel/collections/community/general/zpool_facts_module.html): there’s the ZFS pool name, and a properties selection, again returned under the global name `ansible_zfs_pools`.

(I think these modules should be fixed, but it’s better to wait until data tagging is there before we start deprecating something, since then we can finally properly deprecate return values, including facts 🙂 )

The [PR](https://github.com/ansible-collections/community.general/pull/9750) also falls into this category from my point of view: depending on the module options you get different output (the facts contain or not contain certain units, and some properties might be there or not).

WDYT?

---

<div class="post-metadata">

**Author:** ![flowerysong](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/flowerysong/32/2305_2.png) [@flowerysong](https://forum.ansible.com/u/flowerysong)\
**Post date:** [February 16, 2025, 3:43pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/2 "2025-02-16T15:43:44Z")

</div>

I think that means basically no modules are allowed to return facts, because `ansible.builtin.setup` _also_ gives you different output depending on the module options.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [February 16, 2025, 3:57pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/3 "2025-02-16T15:57:41Z")

</div>

As far as I can see it `ansible.builtin.setup` only allows to determine _which_ facts are returned, and has no options to change the _values_ of returned facts based on module parameters.

---

<div class="post-metadata">

**Author:** ![NomakCooper](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/nomakcooper/32/7309_2.png) [@NomakCooper](https://forum.ansible.com/u/NomakCooper)\
**Post date:** [February 16, 2025, 4:30pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/4 "2025-02-16T16:30:27Z")

</div>

`ansible.builtin.setup` is the filter for `gather_facts`. It returns either the full set of facts or only those that match a specified query. As a result, the returned facts may vary depending on the selection.

On the other hand, `ansible.builtin.mount_facts` adjusts its output based on the specified `source` or allows filtering of the results. Additionally, the collected facts may differ depending on the OS distribution.

The issue is not about which data is collected or included in the results but rather whether these facts should be added to `ansible_facts`.

For example, in the module from my PR, it’s not feasible to collect every single property of every `systemd unit` because properties vary based on the unit type, and some properties may be missed or duplicated ( some units have more than 200 properties. ). This makes it impossible to create a module that gathers all data while allowing filtering through a single option.

The only viable approach is to give users the ability to specify which properties they want to collect and for which units.

Should this data be added to `ansible_facts`, or should it be managed using the `register` function?

---

<div class="post-metadata">

**Author:** ![NomakCooper](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/nomakcooper/32/7309_2.png) [@NomakCooper](https://forum.ansible.com/u/NomakCooper)\
**Post date:** [February 17, 2025, 1:05am UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/5 "2025-02-17T01:05:18Z")

</div>

I have considered all of @felixfontein comments and suggestions on my PR and in this post.  
After conducting some tests and discussing with colleagues, I realized that returning values in `ansible_facts` was not the right choice, at least not in my case.

Modules should return values in `ansible_facts` only when those values are immutable or at least partially stable.

Returning values that might change during the playbook execution can lead to unintended effects and make value management more difficult rather than easier.

For this reason, I decided to close my PR to avoid causing issues for both the repository and the PR itself. Instead, I have opened a new one under the name [`systemd_info`](https://github.com/ansible-collections/community.general/pull/9764).

However, I believe this concept should be more explicitly stated in the documentation, or at the very least, there should be a clear guideline to follow.

Additionally, existing modules should be updated accordingly, though I understand that would be a long-term effort.

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [February 17, 2025, 2:51pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/6 "2025-02-17T14:51:28Z")

</div>

> [@felixfontein](#):
>
> Also the facts output of modules like `ansible.builtin.mount_facts` depends on module options.

It doesn’t, but it does support optionally filtering unwanted mount types/devices. It’s based off the logic in `setup` for gathering mounts, which by comparison is inconsistent across OSes and has hardcoded limitations instead of configuration options.

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [February 17, 2025, 2:55pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/7 "2025-02-17T14:55:16Z")

</div>

There are a lot of default connection facts modules that support configuration options, some of which impact the values returned [Ansible Configuration Settings — Ansible Community Documentation](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#connection-facts-modules). The `gather_facts` action plugin allows configuration for those modules and any configured `FACTS_MODULES` via `module_defaults`.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [February 17, 2025, 5:41pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/8 "2025-02-17T17:41:50Z")

</div>

After 2.19 (if [fixes and updates to inventory intro by bcoca · Pull Request #2416 · ansible/ansible-documentation · GitHub](https://github.com/ansible/ansible-documentation/pull/2416) is merged aka “data tagging”), we plan do deprecate ‘inject’ functionality, so all facts will end up living under `ansible_facts` (with exceptions, like `ansible_local`).

While module authors can chose to do whatever they want, the distinction was intended to be that `_facts` are things inherit to the target machine, mostly that rarely change (hence we allow caching this info) and `_info` was information external to the target itself (for example from AWS account) but somewhat related.

I also plan in the future to remove/break up `setup` into many modules, since `gather_facts` already allows to use multiple different modules (in series or parallel) to customize the ‘gathered facts’ more to each context rather than having a huge and very costly unitary (`setup`) module that most people don’t need.

So IMHO (core has not arrived at a consensus on this) I would allow modules to return facts or not as author sees fit. The categories for `_facts` and `_info` as i describe above are already not followed in some cases, but enforcing that or not is another discussion.

In general I would keep `_facts` for things that are not prone to change, expensive to query and benefit a lot from caching.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [February 17, 2025, 5:47pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/9 "2025-02-17T17:47:07Z")

</div>

> [@NomakCooper](#):
>
> For this reason, I decided to close my PR to avoid causing issues for both the repository and the PR itself. Instead, I have opened a new one under the name [`systemd_info`](https://github.com/ansible-collections/community.general/pull/9764).

`service_facts` already exists and will stay as `_facts` as listing existing services and state should be a mostly ‘stable’ information in most cases. Yes, it can change during a playbook, but that is most things, services in general are expected to be a stable list and stable status, there are contexts where this is not true, but I believe that is the minority right now.

I’m not sure how deep you are going with systemd but I can see it bluring the line easily since it spans soo many more things than ‘services’ at this point, if you just handle services and time/triggered units, this should be fine as `_facts` (IMHO), but can easily be extended to the point that caching this information would be meaningless.

---

<div class="post-metadata">

**Author:** ![NomakCooper](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/nomakcooper/32/7309_2.png) [@NomakCooper](https://forum.ansible.com/u/NomakCooper)\
**Post date:** [February 17, 2025, 6:19pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/10 "2025-02-17T18:19:27Z")

</div>

> [@bcoca](#):
>
> `service_facts` already exists and will stay as `_facts` as listing existing services and state should be a mostly ‘stable’ information in most cases. Yes, it can change during a playbook, but that is most things, services in general are expected to be a stable list and stable status, there are contexts where this is not true, but I believe that is the minority right now.
> 
> I’m not sure how deep you are going with systemd but I can see it bluring the line easily since it spans soo many more things than ‘services’ at this point, if you just handle services and time/triggered units, this should be fine as `_facts` (IMHO), but can easily be extended to the point that caching this information would be meaningless.

The `systemd_info` module was created based on the idea of `service_facts`.

`service_facts` is specifically dedicated to services because it was designed with that focus in mind. However, in my opinion, it is not capable of keeping up with the full capabilities of systemd.

The data collection mechanism for systemd units in `service_facts` is overly simplified, which makes the results unreliable.

The current `service_facts` module returns fairly standardized values by determining property states and mapping them to basic statuses like `stopped`, `running`, and a few others.  
For example, the `state` values do not accurately reflect the actual `SubState` property. As a result, it cannot properly report states like `failed` or `exited`, since it only relies on the `state` return value.

In my opinion, **`systemd`** units are more complex and deserve a dedicated module.

The `systemd_info` module was created to allow users to collect unit properties in a more precise and efficient way. Currently, it supports `.service`, `.target`, `.socket`, and `.mount` units.

For now, this module will remain an `_info` and will return values using `register`.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [February 19, 2025, 9:28pm UTC](https://forum.ansible.com/t/when-should-modules-use-return-ansible-facts/40297/11 "2025-02-19T21:28:07Z")

</div>

> [@bcoca](#):
>
> So IMHO (core has not arrived at a consensus on this) I would allow modules to return facts or not as author sees fit. The categories for `_facts` and `_info` as i describe above are already not followed in some cases, but enforcing that or not is another discussion.

I don’t think this should be enforced. Modules can do whatever they want. But we can have better / more strict guidelines. Folks don’t _have_ to adhere to them in general, but we can enforce them in collections like community.general. (Which is mainly what I’m interested in - having more strict guidelines that everyone _can_ use, and that _are_ used for community.general and some other collections.)

> [@bcoca](#):
>
> In general I would keep `_facts` for things that are not prone to change, expensive to query and benefit a lot from caching.

I think that is something that would make a good guideline 🙂
