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
[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

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.