Introduction
FQCN stands for Fully Qualified Collection Name — the complete namespace.collection.module path that uniquely identifies any Ansible module, plugin, or role. Since Ansible 2.10, content moved from a single package into separate collections, and FQCN became the recommended way to reference modules. Using FQCN prevents ambiguity when multiple collections provide modules with the same short name, and it's required by ansible-lint in production profiles.
In practice, FQCN means writing ansible.builtin.copy instead of copy, or ansible.windows.win_copy instead of win_copy, so the playbook names the exact collection and module Ansible should load.
FQCN Format
namespace.collection.module_name
│ │ │
│ │ └─ Module/plugin name
│ └─ Collection name
└─ Namespace (vendor/org)
# Short name (legacy, ambiguous)
- name: Copy a file
copy:
src: file.txt
dest: /tmp/file.txt
# FQCN (recommended, unambiguous)
- name: Copy a file
ansible.builtin.copy:
src: file.txt
dest: /tmp/file.txt
Why FQCN Matters
1. Avoids Module Name Collisions
# Which "copy" module is this? Built-in? Custom? Third-party?
- copy:
src: file.txt
dest: /tmp/
# Unambiguous — clearly the built-in copy module
- ansible.builtin.copy:
src: file.txt
dest: /tmp/
# Different module entirely — Windows copy
- ansible.windows.win_copy:
src: file.txt
dest: C:\Temp\
2. Future-Proof Your Playbooks
# If a new collection adds a "copy" module, short names break
# FQCN always resolves to the exact module you intended
3. Required by ansible-lint
$ ansible-lint playbook.yml
# WARNING: fqcn[action-core]: Use FQCN for builtin module actions
# playbook.yml:5 Task/Handler: Copy a file
Common FQCN Mappings
Built-in Modules (ansible.builtin)
Short Name → FQCN
──────────────────────────────────────────────
copy → ansible.builtin.copy
file → ansible.builtin.file
template → ansible.builtin.template
command → ansible.builtin.command
shell → ansible.builtin.shell
debug → ansible.builtin.debug
set_fact → ansible.builtin.set_fact
assert → ansible.builtin.assert
lineinfile → ansible.builtin.lineinfile
service → ansible.builtin.service
systemd → ansible.builtin.systemd
apt → ansible.builtin.apt
yum → ansible.builtin.yum
dnf → ansible.builtin.dnf
pip → ansible.builtin.pip
git → ansible.builtin.git
uri → ansible.builtin.uri
get_url → ansible.builtin.get_url
stat → ansible.builtin.stat
user → ansible.builtin.user
group → ansible.builtin.group
cron → ansible.builtin.cron
fetch → ansible.builtin.fetch
unarchive → ansible.builtin.unarchive
raw → ansible.builtin.raw
setup → ansible.builtin.setup
include_tasks → ansible.builtin.include_tasks
import_tasks → ansible.builtin.import_tasks
include_role → ansible.builtin.include_role
import_role → ansible.builtin.import_role
wait_for → ansible.builtin.wait_for
pause → ansible.builtin.pause
fail → ansible.builtin.fail
meta → ansible.builtin.meta
POSIX Collection (ansible.posix)
Short Name → FQCN
──────────────────────────────────────────────
mount → ansible.posix.mount
sysctl → ansible.posix.sysctl
firewalld → ansible.posix.firewalld
authorized_key → ansible.posix.authorized_key
synchronize → ansible.posix.synchronize
at → ansible.posix.at
patch → ansible.posix.patch
Windows Collection (ansible.windows)
win_copy → ansible.windows.win_copy
win_file → ansible.windows.win_file
win_command → ansible.windows.win_command
win_shell → ansible.windows.win_shell
win_service → ansible.windows.win_service
win_reboot → ansible.windows.win_reboot
win_ping → ansible.windows.win_ping
win_get_url → ansible.windows.win_get_url
Community Collections
# PostgreSQL
postgresql_db → community.postgresql.postgresql_db
postgresql_user → community.postgresql.postgresql_user
postgresql_query → community.postgresql.postgresql_query
# Docker
docker_container → community.docker.docker_container
docker_image → community.docker.docker_image
docker_compose_v2 → community.docker.docker_compose_v2
# VMware
vmware_guest → community.vmware.vmware_guest
vmware_guest_info → community.vmware.vmware_guest_info
# AWS
ec2_instance → amazon.aws.ec2_instance
s3_bucket → amazon.aws.s3_bucket
# Kubernetes
k8s → kubernetes.core.k8s
helm → kubernetes.core.helm
How to Find a Module's FQCN
# List all modules from a collection
ansible-doc -l ansible.builtin
# Search for a module
ansible-doc -l | grep copy
# Show module documentation (includes FQCN)
ansible-doc ansible.builtin.copy
# List installed collections
ansible-galaxy collection list
Migrating to FQCN
Manual Migration
# Before (short names)
---
- hosts: webservers
tasks:
- name: Install nginx
apt:
name: nginx
state: present
- name: Copy config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: Start nginx
service:
name: nginx
state: started
enabled: true
# After (FQCN)
---
- hosts: webservers
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Copy config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: Start nginx
ansible.builtin.service:
name: nginx
state: started
enabled: true
Automated Migration with ansible-lint
# ansible-lint can auto-fix FQCN issues
ansible-lint --fix playbook.yml
# Or fix an entire project
ansible-lint --fix .
Search and Replace
# Careful with sed — only use for simple cases
# Better to use ansible-lint --fix
# Example: find all non-FQCN module usage
grep -rn '^\s*- \(copy\|file\|template\|command\|shell\|debug\):' roles/
FQCN for Plugins and Filters
FQCN applies to everything, not just modules:
# Filters
"{{ my_list | ansible.builtin.unique }}"
"{{ my_string | ansible.builtin.regex_search('pattern') }}"
"{{ my_var | ansible.builtin.default('fallback') }}"
# Lookup plugins
"{{ lookup('ansible.builtin.env', 'HOME') }}"
"{{ lookup('ansible.builtin.file', '/etc/hostname') }}"
"{{ query('ansible.builtin.pipe', 'date') }}"
# Connection plugins
ansible_connection: ansible.builtin.ssh
ansible_connection: ansible.windows.winrm
# Callback plugins
# In ansible.cfg:
[defaults]
callbacks_enabled = ansible.posix.timer, ansible.builtin.profile_tasks
# Strategy plugins
[defaults]
strategy = ansible.builtin.linear
Common Mistakes
# ❌ MISTAKE 1: Wrong namespace
- community.builtin.copy: # Wrong! "community.builtin" doesn't exist
# FIX:
- ansible.builtin.copy:
# ❌ MISTAKE 2: Forgetting to install the collection
- community.postgresql.postgresql_db:
name: mydb
# Error: "couldn't resolve module/action 'community.postgresql.postgresql_db'"
# FIX: ansible-galaxy collection install community.postgresql
# ❌ MISTAKE 3: Using FQCN for roles without full path
roles:
- geerlingguy.docker # This is a role name, not FQCN
# Role FQCN would be the collection namespace if packaged as one
# ❌ MISTAKE 4: Mixing short and FQCN in same project
# Pick one style and be consistent — FQCN everywhere is safest
# ❌ MISTAKE 5: FQCN in requirements.yml
# requirements.yml uses collection names, not module FQCNs:
collections:
- name: community.postgresql # Collection name, not module FQCN
version: ">=3.0.0"
ansible.cfg Collection Search
# ansible.cfg
[defaults]
# Where Ansible looks for collections
collections_paths = ~/.ansible/collections:/usr/share/ansible/collections
# Collections scan — shows which collection provides a module
# ansible-doc -t module ansible.builtin.copy
Related Articles
- Ansible Collections Path
- Ansible Galaxy Install Collections
- Ansible ansible-lint Guide
- Ansible Best Practices
- Ansible Beginners Guide
Conclusion
Use FQCN everywhere. It's unambiguous, future-proof, lint-compliant, and the official recommendation since Ansible 2.10. The most common prefix is ansible.builtin. for core modules. Run ansible-lint --fix to automatically convert existing playbooks from short names to FQCN. The small upfront effort of typing the full path saves debugging time when collections evolve or when multiple collections share module names.