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

IssueSolution
"directory already exists"Use --force to overwrite
Role not found after installCheck roles_path in ansible.cfg
Collection not foundRun ansible-galaxy collection list to verify install path
Version conflictPin versions in requirements.yml
"permission denied" on installUse --roles-path for local install

Best Practices

  1. Always use init — don't create role directories manually
  2. Fill in meta/main.yml — platforms, dependencies, and tags
  3. Use requirements.yml — pin versions for reproducible builds
  4. One role per concern — nginx, postgresql, monitoring as separate roles
  5. Default variables in defaults/ — keep vars/ for non-overridable values
  6. 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.