Ansible Galaxy Init — Create Role and Collection Scaffolding
Introduction
ansible-galaxy init generates the complete directory structure for Ansible roles and collections. Instead of manually creating 8+ directories and placeholder files, one command sets up the standard layout with tasks/main.yml, defaults/main.yml, handlers/main.yml, meta/main.yml, README, and test files — ready for you to fill in.
Create a Role
# Basic role creation
ansible-galaxy init my_role
# Create in a specific path
ansible-galaxy init --init-path roles/ nginx
# Force overwrite existing
ansible-galaxy init --force my_role
Generated Structure
my_role/
├── defaults/
│ └── main.yml # Default variables (lowest precedence)
├── files/ # Static files for copy/script modules
├── handlers/
│ └── main.yml # Handler definitions
├── meta/
│ └── main.yml # Role metadata (dependencies, platforms)
├── tasks/
│ └── main.yml # Main task list
├── templates/ # Jinja2 templates
├── tests/
│ ├── inventory # Test inventory
│ └── test.yml # Test playbook
├── vars/
│ └── main.yml # Role variables (high precedence)
└── README.md # Documentation
Fill in the Role
# defaults/main.yml — configurable defaults
nginx_port: 80
nginx_worker_processes: auto
nginx_worker_connections: 1024
# tasks/main.yml — main task list
---
- name: Install Nginx
ansible.builtin.package:
name: nginx
state: present
- name: Configure Nginx
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart Nginx
- name: Start Nginx
ansible.builtin.systemd:
name: nginx
state: started
enabled: true
# handlers/main.yml
---
- name: Restart Nginx
ansible.builtin.systemd:
name: nginx
state: restarted
# meta/main.yml
---
galaxy_info:
author: Your Name
description: Install and configure Nginx
license: MIT
min_ansible_version: "2.15"
platforms:
- name: Ubuntu
versions: [jammy, noble]
- name: EL
versions: [8, 9]
galaxy_tags:
- nginx
- web
- reverse_proxy
dependencies:
- role: common
Create a Collection
# Create collection structure
ansible-galaxy collection init my_namespace.my_collection
# With custom path
ansible-galaxy collection init --init-path ./collections my_namespace.my_collection
Generated Structure
my_namespace/my_collection/
├── docs/
├── galaxy.yml # Collection metadata
├── meta/
│ └── runtime.yml # Runtime metadata
├── plugins/
│ ├── README.md
│ ├── modules/ # Custom modules
│ ├── module_utils/ # Shared module code
│ ├── inventory/ # Inventory plugins
│ ├── filter/ # Filter plugins
│ ├── lookup/ # Lookup plugins
│ └── callback/ # Callback plugins
├── README.md
├── roles/ # Roles within collection
└── tests/ # Integration tests
galaxy.yml
namespace: my_namespace
name: my_collection
version: 1.0.0
readme: README.md
authors:
- Your Name <you@example.com>
description: My custom Ansible collection
license:
- MIT
repository: https://github.com/you/my_collection
documentation: https://github.com/you/my_collection/docs
tags:
- infrastructure
- automation
dependencies:
ansible.builtin: ">=2.15.0"
build_ignore:
- .gitignore
- .pytest_cache
Install Roles and Collections
# Install from Galaxy
ansible-galaxy install geerlingguy.nginx
ansible-galaxy collection install community.general
# Install from requirements file
ansible-galaxy install -r requirements.yml
ansible-galaxy collection install -r requirements.yml
# Install to custom path
ansible-galaxy install --roles-path ./roles geerlingguy.nginx
requirements.yml
# Roles
roles:
- name: geerlingguy.nginx
version: "3.2.0"
- name: geerlingguy.postgresql
- src: https://github.com/org/custom-role.git
scm: git
version: main
name: custom_role
# Collections
collections:
- name: community.general
version: ">=9.0.0"
- name: amazon.aws
version: "8.0.0"
- name: community.postgresql
Project Layout Best Practices
ansible-project/
├── ansible.cfg
├── inventory/
│ ├── production/
│ │ ├── hosts.yml
│ │ ├── group_vars/
│ │ └── host_vars/
│ └── staging/
├── playbooks/
│ ├── site.yml
│ ├── deploy.yml
│ └── maintenance.yml
├── roles/
│ ├── common/ # ansible-galaxy init --init-path roles/ common
│ ├── nginx/ # ansible-galaxy init --init-path roles/ nginx
│ └── postgresql/
├── collections/
│ └── requirements.yml
├── group_vars/
│ ├── all.yml
│ └── webservers.yml
├── host_vars/
├── files/
├── templates/
└── requirements.yml
List and Manage Roles
# List installed roles
ansible-galaxy list
# Remove a role
ansible-galaxy remove geerlingguy.nginx
# Search Galaxy
ansible-galaxy search nginx
ansible-galaxy search nginx --platforms Ubuntu
# Get role info
ansible-galaxy info geerlingguy.nginx
Build and Publish Collections
# Build collection tarball
ansible-galaxy collection build
# Publish to Galaxy
ansible-galaxy collection publish my_namespace-my_collection-1.0.0.tar.gz
# Publish to private Automation Hub
ansible-galaxy collection publish \
my_namespace-my_collection-1.0.0.tar.gz \
--server https://hub.example.com/api/galaxy/content/inbound/
Troubleshooting
| Issue | Solution |
|---|---|
| "directory already exists" | Use --force to overwrite |
| Role not found after install | Check roles_path in ansible.cfg |
| Collection not found | Run ansible-galaxy collection list to verify install path |
| Version conflict | Pin versions in requirements.yml |
| "permission denied" on install | Use --roles-path for local install |
Best Practices
- Always use
init— don't create role directories manually - Fill in
meta/main.yml— platforms, dependencies, and tags - Use
requirements.yml— pin versions for reproducible builds - One role per concern — nginx, postgresql, monitoring as separate roles
- Default variables in
defaults/— keepvars/for non-overridable values - Document in README — role variables, requirements, example playbook
Conclusion
ansible-galaxy init eliminates the boilerplate of creating role and collection structures. One command generates the complete directory layout with all standard files — defaults, tasks, handlers, meta, templates, and tests. Combined with requirements.yml for dependency management and Galaxy for sharing, it's the foundation of reusable, maintainable Ansible automation.