What Is New in Ansible 14
| Category | Highlights |
|---|---|
| New Features |
Action plugins can now directly register variables via register_host_variables on ActionBase --
ending years of workarounds with insecure fact injection;
new register projections allow mapping multiple variable names to Jinja expressions in a single task;
new _task implicit object exposes current task result without requiring register;
PowerShell modules can now run on POSIX hosts via pwsh;
community.mysql renamed to ansible.mysql with redirect stubs included.
|
| Improvements |
ansible-galaxy now blocks installation of collections whose requires_ansible version mismatches the running ansible-core by default;
default callback gains display_included_hosts, configurable YAML line width, and variable-controlled display_skipped_hosts;
file and stat modules return disk_usage_bytes;
slurp gets an armor option to disable base64 encoding;
community.sops load_vars now sets variables natively on ansible-core 2.21+;
community.general 13.0.0 ships with all PSF 2.0 licensed code removed (GPLv3+/MIT/BSD-2 only).
|
| Bug Fixes |
Task conditionals (when, until, failed_when) now always produce a descriptive, recoverable failure instead of silent warnings or controller crashes;
--start-at-task now correctly starts at the specified task;
apt fixes for >= operator on uninstalled packages, comma-separated recommends, and missing lists directory;
copy honors directory_mode with remote_src=True;
to_yaml/to_nice_yaml restores pre-2.19 vault decryption behavior;
dnf fixes arch-specific installs and module upgrade handling.
|
| Breaking Changes |
psrp connection plugin changes the default negotiate_service from WSMAN to host -- set ansible_psrp_negotiate_service=WSMAN to restore old behavior;
ansible-galaxy now rejects collections incompatible with the current ansible-core version (set COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH=ignore to revert);
deprecated ansible.builtin.paramiko connection plugin removed;
interpreter_discovery drops auto_legacy and auto_legacy_silent options.
|
| Deprecations |
apt_key and apt_repository deprecated in favor of deb822_repository;
get_all_subclasses(), load_platform_subclass(), get_platfrom() from ansible.module_utils.basic deprecated (removal in 2.24);
ansible.module_utils.six deprecated (removal in 2.24);
task failure inferred from non-zero rc without explicit failed key will be deprecated in core 2.22;
junipernetworks.junos collection removed from Ansible 14 as unmaintained.
|
What is the biggest change in ansible-core 2.21 that ships with Ansible 14?
The single most impactful change in ansible-core 2.21 is the new ability for action plugins to directly register variables at multiple precedence layers using register_host_variables on ActionBase. This has been a long-standing pain point: before 2.21, any action plugin that needed to inject variables -- think community.sops.load_vars, custom secret-loading plugins, dynamic inventory enrichment -- had no clean path. The only workaround was returning data under ansible_facts, which used the insecure INJECT_FACTS_AS_VARS mechanism. That mechanism was deprecated in 2.19, leaving a gap that generated noisy deprecation warnings across every task that consumed sops-encrypted variables.
With ansible-core 2.21, this is fully resolved. Community collections like community.sops have already updated their load_vars action to use the new API, controlled via a new return_method option defaulting to auto (which automatically uses the native variable API on 2.21+ and falls back to ansible_facts on older cores). In practice, if you're running any custom action plugins that set variables, this is the migration path to test first.
A complementary feature -- register projections -- allows a single task to map multiple variable names to Jinja expressions, replacing common patterns that previously required a separate set_fact task. Combined with the new _task implicit object (which exposes _task.result without requiring a named register), Ansible 14 substantially reduces boilerplate in data-transformation playbooks.
# New in ansible-core 2.21: register projections
- name: Parse connection string
community.postgresql.postgresql_query:
db: mydb
query: "SELECT version()"
register:
pg_version: _task.result.query_result[0].version
pg_changed: _task.result.changed
Does upgrading to Ansible 14 break any existing playbooks or connection settings?
There are two breaking changes worth auditing before upgrading. The first affects WinRM/PSRP users: the psrp connection plugin now defaults negotiate_service to host instead of WSMAN. This aligns with how native PowerShell remoting works on Windows and improves Kerberos compatibility, but if your existing infrastructure relies on the old SPN format, you must explicitly set ansible_psrp_negotiate_service=WSMAN in host vars. There was no deprecation period for this change.
The second breaking change affects collection installation workflows. ansible-galaxy install and ansible-galaxy collection install|download now refuse to install collections whose requires_ansible constraint is incompatible with the running ansible-core version. Previously, galaxy would install the collection and fail silently at load time. Most teams relying on CI pipelines will see this as a useful guardrail, but automation scripts that installed mismatched collections intentionally will need the new COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH=ignore config flag.
Watch out for the removal of the legacy ansible.builtin.paramiko connection plugin and the auto_legacy/auto_legacy_silent interpreter discovery options -- both were deprecated for several releases and are now gone entirely.
Which collections were added, renamed, or removed in Ansible 14?
The most significant collection-level change in Ansible 14 is the removal of junipernetworks.junos. This collection was flagged as unmaintained across Ansible 11, 12, and 13 with repeated warnings that it would be dropped if no maintainer stepped forward. In Ansible 14, that removal has happened. If you automate Juniper Junos devices using this collection, you must install it manually via ansible-galaxy collection install junipernetworks.junos going forward -- it will no longer arrive with the Ansible package.
The second major rename is community.mysql, which has been rebranded to ansible.mysql. Ansible 14 ships both: the old community.mysql namespace now contains only deprecated redirect stubs pointing to ansible.mysql, and the full implementation lives under the new name. The redirect stubs will remain until Ansible 16. Most teams will want to update FQCNs from community.mysql to ansible.mysql now to avoid accumulating redirect warnings in playbook output.
On the collection update front, community.general 13.0.0 (bundled in Ansible 14) completed a licensing cleanup: all PSF 2.0 licensed code has been removed. The collection is now uniformly GPLv3+, MIT, or BSD-2-clause. Additionally, all module utils, plugin utils, and doc fragments in community.general are now private API -- importing them from outside the collection is no longer supported and may break on any release.
What task conditional and loop improvements ship in Ansible 14?
Ansible 14 overhauls how task conditionals behave under error conditions. Previously, an error inside a when, until, or failed_when expression could produce inconsistent outcomes -- sometimes a warning, sometimes a lost task result, sometimes an unrecoverable controller crash. With ansible-core 2.21, any error in a task conditional always produces a descriptive, recoverable task failure that respects ignore_errors. This matters if you have complex Jinja expressions in conditionals referencing undefined or typed variables.
The break_when loop keyword gets several consistency fixes: a break_when_result key is now always present in loop results when the expression is used, and a break_when_suppressed_exception key surfaces when a failing break_when expression masks an existing task exception. The registered result of a loop task no longer includes a spurious skipped: false key when no items were skipped -- this cleans up conditional logic that tested for that key.
The ignore_errors and ignore_unreachable keywords now behave consistently in loops: if the expression resolves to True for any loop item, errors are ignored for the entire task. Previously, per-item evaluation could produce surprising partial-failure states.
What Windows and PowerShell improvements are in Ansible 14?
Ansible 14 introduces cross-platform PowerShell module execution -- PowerShell modules can now run on POSIX hosts using the pwsh interpreter. This is a meaningful expansion for teams that have standardized on PowerShell for automation logic but need to target Linux or macOS systems. Most PowerShell module utils work correctly; the notable exception is any util that depends on Windows-specific APIs. The Ansible.Basic.cs module utility for input and output handling is confirmed compatible.
The psrp connection plugin adds two new options via host variables: ansible_psrp_certificate_key_password for decrypting encrypted certificate keys, and ansible_psrp_no_profile to prevent loading the Windows user profile on the remote host during task execution. Both require pypsrp>=0.9.0. Additionally, psrp now correctly classifies ReadTimeout exceptions as unreachable (rather than fatal), which allows ignore_unreachable to function correctly in timeout scenarios.
ansible-test gains PowerShell support for managed containers and remotes, and the updated managed remote images now include Alpine 3.23, Fedora 43, FreeBSD 15.0, RHEL 10.1, RHEL 9.7, and macOS 26.3. macOS managed remotes have also switched from x86_64 to aarch64.
Frequently Asked Questions about Ansible 14
Does upgrading to Ansible 14 require changes to existing playbooks?
Most playbooks continue to work without changes unless they rely on junipernetworks.junos (now removed), the psrp connection plugin with the old WSMAN SPN default, the paramiko connection plugin (removed), or auto_legacy interpreter discovery (removed); teams using community.mysql should also update FQCNs to ansible.mysql to avoid deprecation noise.
How do I install Ansible 14?
Run python3 -m pip install ansible==14.0.0 --user to install the full community package, which pulls in ansible-core 2.21.0 automatically; alternatively, use the galaxy-requirements.yaml file from the ansible-build-data repository to install only the bundled collections against an older ansible-core version.
What replaced the insecure fact injection workaround for action plugins?
ansible-core 2.21 introduces the register_host_variables method on ActionBase, allowing action plugins to directly register variables at multiple precedence layers without going through ansible_facts or the deprecated INJECT_FACTS_AS_VARS mechanism; community.sops load_vars uses this new API automatically on ansible-core 2.21 via its return_method option set to auto.
What happens if I run ansible-galaxy install against a collection that requires a newer ansible-core?
Starting with ansible-core 2.21 (shipped with Ansible 14), ansible-galaxy will refuse to install or download collections whose requires_ansible version constraint is incompatible with the running ansible-core; to restore the previous behavior and force installation anyway, set the COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH configuration item to ignore.
Is the junipernetworks.junos collection permanently gone from Ansible 14?
It is removed from the bundled Ansible 14 package due to being unmaintained, but it can still be installed independently with ansible-galaxy collection install junipernetworks.junos.
What is the ansible.mysql collection and how does it relate to community.mysql?
The community.mysql collection was renamed to ansible.mysql; Ansible 14 ships both, but community.mysql now contains only deprecated redirect stubs pointing to ansible.mysql, and these stubs will be fully removed in Ansible 16, so updating all FQCNs from community.mysql to ansible.mysql now is the recommended migration path.