The problem
ansible-galaxy can install collections but has no command to remove them.
Collections can sit in several places: the paths in COLLECTIONS_PATHS
(configured in ansible.cfg or ANSIBLE_COLLECTIONS_PATH), project
collections/ directories, and ansible_collections in site-packages. To
remove one, users delete its directory with rm -rf in every place a copy
might be, and nothing checks whether another collection still depends on it.
The demand is documented:
- ansible/ansible#67759, "Add ansible-galaxy collection uninstall", has 179 reactions (174 thumbs up) and 20 comments and has been open since February 2020. Users there report ending up with two versions of the same collection and only knowing where one of them is.
- Two upstream pull requests were closed without merging: #73464 (2021, closed 2022) and #84738 (2025, closed March 2026; it removed only the requested collections, without dependency handling).
- Red Hat has a knowledge base article, "How to Uninstall an Ansible Collection".
ade uninstallfrom ansible-dev-environment works only on the site-packages of the virtual environment it manages and does not check dependencies.
How it works
galaxy-uninstall asks Ansible
where collections are: ansible-config dump gives the configured search paths
in order, and ansible-galaxy collection list --format json gives every
installed copy. It does not import Ansible, so ansible.cfg,
ANSIBLE_COLLECTIONS_PATH and -p are honoured as Ansible itself reads them.
From this it determines which copy Ansible loads and which copies are shadowed
by an earlier path. Before removing a collection it reads the dependencies
from MANIFEST.json and refuses if another installed collection depends on it
and no other copy stays installed. --deps also removes dependencies that no
remaining collection needs, and --shadowed removes copies that Ansible never
loads.
Removing a copy deletes ansible_collections/<ns>/<name>, the .info
directory that ansible-galaxy writes, and the namespace directory if it is
then empty. Collections that belong to a pip package and directories with a
.git checkout are not deleted, and symlinked collections are unlinked without
touching the target.
The README shows a real run (paths shortened) for a project with demo.app,
which depends on demo.base, and two more copies of demo.base:
$ galaxy-uninstall --list
demo.app 1.0.0 ~/proj/collections/ansible_collections [active]
demo.base 1.0.0 ~/proj/collections/ansible_collections [active]
demo.base 2.0.0 ~/.ansible/collections/ansible_collections [shadowed by ~/proj/collections/ansible_collections]
demo.base 2.0.0 /venv/lib/python3.12/site-packages/ansible_collections [shadowed by ~/proj/collections/ansible_collections]
$ galaxy-uninstall demo.base --all
refusing: demo.app 1.0.0 in ~/proj/collections/ansible_collections depends on demo.base
remove the dependents too, or pass --force
$ galaxy-uninstall demo.app --deps -n
Will remove:
demo.app 1.0.0 ~/proj/collections/ansible_collections/demo/app
demo.base 1.0.0 ~/proj/collections/ansible_collections/demo/base
Afterwards Ansible loads demo.base 2.0.0 in ~/.ansible/collections/ansible_collections
The tool is a Python CLI that uses only the standard library.
Testing
The unit tests build directory trees with collections and replace the Ansible
commands with fixed output. They cover the search order and shadowing, the
selection of a copy when several are installed, the dependency check,
transitive orphans for --deps, the detection of pip-owned collections and git
checkouts, removal of the .info and namespace directories, symlinks, dry
runs, and the refusal to delete without -y when stdin is not a terminal.
The end-to-end test uses a real ansible-core. It builds demo.base 1.0.0 and
2.0.0 and demo.app with ansible-galaxy, installs them offline into two
paths, removes copies with galaxy-uninstall and checks with ansible localhost
which copy a filter plugin is loaded from. CI runs all tests with ansible-core
2.15, 2.17 and the latest release (2.21). One difference turned up there:
ansible-core 2.15 and 2.17 abort ansible-galaxy collection list with an error
when none of the collection paths exists yet, where newer versions print an
empty list. The tool treats that error as an empty listing.
Limitations
- The search order is the one
ansibleandansible-playbookuse outside a playbook directory. Acollections/directory next to a playbook is only considered when it is passed with-p. - Version ranges in dependencies are not evaluated. A dependency counts as satisfied while any copy of it stays installed.
--depscannot know which collections were installed on purpose, because ansible-galaxy keeps no record of that.-nshows the plan first, and--keepprotects a collection.- Roles and
requirements.ymlfiles are not handled.
The code and installation instructions are at github.com/Jwrede/galaxy-uninstall.