Ansible: What to Do with Standalone Roles?

3 September, 2026

Matthias Döhler

by | Sep 3, 2026

Last updated: August 27, 2026 · Reading time: 9–11 minutes

Ansible has been using so-called ” Collections” since 2019. They are the primary method for sharing Ansible content with others. But even before Ansible Collections existed, roles were already used for this purpose. In today’s ecosystem, both are still present. Find out now what “Roles” and “Collections” are all about and which one you should choose today.

The Most Important Points in 30 Seconds

  • Roles are functions; collections are the format in which they are distributed. The two complement each other; Collections do not replace roles.
  • Standalone roles are rarely the focus of development anymore and can only be distributed via GitHub through Ansible Galaxy.
  • Custom plugins (modules, filters, etc.) in standalone roles cannot be easily used via FQCN and carry the risk of name collisions.
  • The solution: Move standalone roles into an existing or new collection. A “miscellaneous” collection is also a valid option.

What is an Ansible role, and what is a collection?

In the past, if you wanted to make Ansible code available to others, the choice was simple: roles!
Ansible roles are a collection of variables, tasks, plugins, and other extras that, when used together, primarily save time.

You can think of roles as being like functions in programming. They perform tasks, have a specific use case, and can be called with customized parameters as needed.
For roles, these parameters are the variables. A role typically has predefined standard variables that the user can modify to customize the role’s behavior—that is, the function’s behavior. A role that sets up a web server could, for example, have the server listen on port 8888 instead of port 80 if you adjust the corresponding variable.

Collections are the modern alternative to roles. They do not replace roles; rather, they are explicitly intended for distributing Ansible content. This content includes modules and various types of plugins, such as inventory or filter plugins, as well as roles. Thus, collections can be viewed as repositories for content, while roles themselves represent specific content.

Should I use roles or collections?

The short answer: Yes!

Roles are still an essential part of Ansible today. The collections have simply relieved the roles of their distribution tasks. All Ansible content should be organized into collections these days. This also applies to roles, especially when modules or plugins are to be made available at the same time.

Standalone roles—that is, roles that do not follow the modern approach and are therefore not part of a collection— should be avoided.

Reasons

Little Focus on Development for the Ansible Role

One fairly obvious reason is the focus on collections. In recent years, Collections have become increasingly important and sophisticated.
Although there are no official plans from the Ansible project, given that roles can now be part of a collection, it is unclear how much longer standalone roles will be supported.
Even today, customizations and new features are primarily limited to Collections, which is why standalone roles can only benefit from them to a limited extent.

Distribution and Ansible Galaxy

Ansible Galaxy is often used to distribute Ansible roles and collections. Collections can be made available by uploading them as tarballs via the web UI or CLI.
Roles, on the other hand, can only be imported from GitHub. Ansible Galaxy handles downloading and making the content—one tarball per Git tag—available. In this process, the entire contents of the repository end up in the final tarball. Tests, CI/CD files, etc., are therefore unnecessarily included in the distribution.
With Collections, on the other hand, you can exclude files, and there is no dependency on GitHub. Tar Ball collections can be created manually and uploaded via the web UI or CLI. It doesn’t matter where the repository is located or on which platform it is hosted.

Using Content from an Ansible Role

Roles should not be used to distribute or make plugins (modules, filters, etc.) available. This is because plugins from roles cannot (easily) be used outside the role itself.

I would like to illustrate this issue with an example. A role with its own plugins—in this case, a module and a filter—might look something like this:

netways.myrole/
├── defaults
│   └── main.yml
├── filter_plugins
│   └── myfilter.py
├── handlers
│   └── main.yml
├── library
│   └── mymodule.py
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
└── vars
    └── main.yml

The following code blocks show the contents of the relevant files.

ibrary/mymodule.py:

from ansible.module_utils.basic import AnsibleModule
DOCUMENTATION = '''
name: mymodule
short_description: Test module
description:
  - Just a test module that echoes its input
version_added: 1.0.0
author:
  - Matthias Döhler
options:
  name:
    description:
      - A name to echo
    required: true
    type: str
'''
EXAMPLES = '''
mymodule:
  name: "John"
'''
def main():
    module = AnsibleModule(
        argument_spec=dict(
            name=dict(required=True, type='str'),
        )
    )
    args = module.params
    module.exit_json(
        changed=False,
        name=args['name'],
        echoed_name=args['name'],
    )
if __name__ == '__main__':
    main()
filter_plugins/myfilter.py:

def my_filter(_input):
    result = f'"{_input}" went through "myfilter"'
    return result
class FilterModule(object):
    def filters(self):
        return {
            "myfilter": my_filter,
        }

A filter is defined using a function that transforms a passed parameter and returns the result.
The ` FilterModule ` class handles the internal translation of the filter name to the corresponding function.

If the filter plugin is now used in a play, the following error occurs.

play.yml:

- name: Test
  hosts: localhost
  tasks:
    - name: Short name
      ansible.builtin.debug:
        msg: "{{ 'my custom message' | myfilter }}"
    - name: FQCN
      ansible.builtin.debug:
        msg: "{{ 'my custom message' | netways.myrole.myfilter }}"
TASK [Short name] ****************************************************************************************************************************************************
[ERROR]: Task failed: Finalization of task args for 'ansible.builtin.debug' failed: Error while resolving value for 'msg': Syntax error in template: No filter named 'myfilter'. 

Ansible could not find the filter myfilter. The attempt to use the FQCN also fails.

There are two solutions here:

Performing the Role

If the role is used directly within a play, plugins from that role can be called and used within the same play.

play.yml:

- name: Test
  hosts: localhost
  roles:
    - netways.myrole
  tasks:
    - name: Short name
      ansible.builtin.debug:
        msg: "{{ 'my custom message' | myfilter }}"
    - name: FQCN
      ansible.builtin.debug:
        msg: "{{ 'my custom message' | netways.myrole.myfilter }}"

However, this gives rise to three problems.


The FQCN cannot be used in this context. Ansible does not recognize the notation <Rollenname>.<Pluginname>. Consequently, Ansible cannot find ` netways.myrole.myfilter `, and the second task still fails.

Technically speaking, the plugins can be accessed at ansible.legacy.<Name des Plugins>.

The second problem is closely related to the first: the possibility of name collisions.
The function ` my_filter ` could also be exported under the name ` first `, for example. The same filter could then be used in the background via the shorthand forms myfilter and first.
This would overwrite the filter ” ansible.builtin.first ” in its shorthand form, which could lead to significant problems later on during Playbook execution.

A role X that is used according to netways.myrole may not use an FQCN for filters and instead relies on the shorthand notation first. As a result, however, it effectively uses the filter first from netways.myrole.
Through this mechanism, roles can even influence one another, which makes problem-solving more difficult.

To make matters worse, the FQCN is often omitted when using filters in roles within modern collections. In fact, Ansible largely avoids name collisions here by not making filters from additional collections available as shorthand at all. So, for custom filters, the FQCN is mandatory here anyway.

The third problem is obvious: The role must be carried out. This means that the tasks associated with the role must also be executed each time so that you can access the plugins later on. That will rarely be the desired behavior.
If there are no tasks in the role, this isn’t a problem. However, a role without tasks is extremely rare and does not reflect either the new collection-based approach or the old role-based approach.

Bonus problem: Some types of plugins, such as inventory plugins, must be loaded before the playbook runs. The trick of doing the roll first doesn’t work here. We have a chicken-and-egg problem.

Configuration Changes

Ansible uses different search paths for plugins. Plugins from collections are automatically available, provided that Ansible can locate the collections. So the collections just need to be copied or installed to the correct path.
For plugins outside of Collections—whether they are individual files or in old roles—the Ansible search path must be expanded.

The following sample configuration extends the search paths to include a folder containing custom inventory plugins.

[defaults]
inventory_plugins=/usr/share/ansible/plugins/inventory:/home/matthias/ansible_plugins/inventory

The problem with this approach quickly becomes apparent when plugins are also intended to be used by standalone roles:

[defaults]
inventory_plugins=/usr/share/ansible/plugins/inventory:/home/matthias/ansible_plugins/inventory:/home/matthias/ansible_roles/role1/inventory_plugins:/home/matthias/ansible_roles/role2/inventory_plugins

For each standalone role, the search path must be adjusted accordingly. In addition, each type of plugin has its own configuration option, which further increases the maintenance effort. The time (and stress) involved here simply cannot be justified.

In both scenarios, it’s also important to keep in mind that this extra effort—the workarounds, the search paths, etc.—is not something the role creator can take off the users’ hands. Every user in such a role faces exactly the same problem and must implement a solution.

Ansible setup with lots of old roles?
Our consultants will assist you with migrating to Collections and with the day-to-day operation of your Ansible environment.
Request a free consultation →

What now?

To ensure compatibility with Ansible’s modern approach, it is recommended to move standalone roles —especially those that use plugins —into collections. Roles can be grouped into Collections by topic or added to a “miscellaneous” Collection if there is no thematic connection. Creating a new collection with just one role is also a valid approach.

The example role mentioned above could have the following structure as a collection:

netways/misc/
├── galaxy.yml
├── plugins
│   ├── filter
│   │   └── myfilter.py
│   └── modules
│       └── mymodule.py
└── roles
    └── myrole
        ├── defaults
        │   └── main.yml
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        └── vars
            └── main.yml

Basically, the role is copied to the ` roles/` folder within the collection, and the contents are moved from ` library/ ` to ` plugins/modules/ ` within the collection. For other types of plugins, the contents of the corresponding folder in the role are moved to plugins/<Art des Plugins>/.

Plugin TypePath in the rolePath in the Collection
Modulelibrary/plugins/modules/
Filterfilter_plugins/plugins/filter/
Testtest_plugins/plugins/test/

Following the restructuring and integration of a standalone role into a collection, the plugins can now also be accessed via FQCN. The plugins should still be tested to ensure they are working properly, but as a general rule, they should continue to function as usual. Any existing references to the shorthand notation for plugins should be replaced with the appropriate FQCN. Now all that’s left to do is replace references to the old role in Playbooks with references to the new role within the collection.

Conclusion: Ansible Role or Collection

“Never change a running system” is often a good motto for stability. But when it comes to automation in particular, it’s important to stay on top of things so you can benefit from improvements, quality-of-life features, and new possibilities. Collections have been around for quite some time now. All in all, it might actually take even more time to use old, standalone roles and work around problems, simply because the convenient features of Collections are missing here.
If you notice any issues with handling standalone roles in the near future, or if you become aware of your own workarounds, that’s probably a good time to dive fully into the era of collections.

How did you like our article?