Ansible Roles: Directory Structure

Reading Time: 4 minutes

Hi readers, in this blog we will be discussing about Ansible roles and the directory structure used in Ansible. Above all, we will be looking at what different directories in a role do and how they can be created.

What are Ansible Roles?

According to the official Ansible documentation ‘roles are ways of automatically loading certain vars_files, tasks, and handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users’. In other words, roles are a feature of Ansible that facilitate reuse and further promote modularization of configuration.

The role is the primary mechanism for breaking a playbook into multiple files. Therefore, this simplifies writing complex playbooks, and it makes them easier to reuse. The breaking of playbook allows you to logically break the playbook into reusable components.

Directory Structure:

The concept of an Ansible role is simple; it is a group of variables, tasks, files, and handlers stored in a standardised file structure. The difficult part is to recall the directory structure, but there is help. The ansible-galaxy command has a sub-command that will create a directory skeleton for our role.

To create a role using the ansible-galaxy command, we can simply use the below syntax in our terminal:

ansible-galaxy init <ROLE_NAME>

Running this command will give us a basic directory structure in our current working directory and this directory structure will be like the one below:

├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

These many number of files and directories may appear to be difficult to work with, but they are fairly easy to understand. Above all, we always have the freedom to write our tasks and variable into other files but we must include directives into the directory’s main.yml file. Let us look into the use of these different directories in our role.


The defaults directory is for defining the variable defaults. The variables in default have the lowest priority thus becoming easy to override. If definition of a variable is nowhere else, the variable in defaults/main.yml will be used.


We use the files directory to add files that are needed by provisioning machine, without modification. Mostly, we use copy task for referencing files in the files directory. The most interesting part about this is that Ansible does not require a path for resources stored in files directory when working in the role.


The handlers directory is used for storing Ansible handlers. Handlers are tasks that may be flagged during a play to run at the play’s completion. We can have as many and as few handlers as we need.


We use the meta directory to store authorship information which is useful if we choose to publish our role on The metadata of an Ansible role consists of author, supported platforms, and dependencies.


The task directory is where we write most of our roles which includes all the tasks our role will perform. We write each series of tasks in a separate file and include them into the main.yml file in the tasks directory.


We use the template directory to also add files to our machine(similar to files directory). Only difference between template and files directories is that the template directory supports alteration (modification). Jinja2 language to used to create these alteration. Most software configuration files become templates.


We can use the tests directory if we have built and automated testing process around our role. This directory contains a sample inventory and a test.yml file.


This is where we create variable files that define necessary variables for our role. The variables defined in this directory are meant for role internal use only. Also, it is a good idea to namespace our role variable names, to prevent potential naming conflicts with variables outside of our role.

Creating a Simple Ansible Role:

We can make our Ansible roles as simple and as complex as needed. Let us start by creating a simple role that will be updating all the packages of a remote system using apt package manager. We will only be creating a minimal role and we will be looking at how to use it in our playbook.

Setting Up Our Ansible Role:

First, we will need to create our role. We can create each directory manually, but it is simpler to just let ansible-galaxy do this work for us:

ansible-galaxy init apt_update

We will then get the following as our console output:

- Role apt_update was created successfully

Creating Our Tasks:

Next, we will be creating our task in the role to update the packages of our remote system.

# tasks file for apt_update
- apt: 
     name: "*"
     state: latest

We will be adding the above information to our tasks/main.yml file.

Since, we are looking to make a simple role, we are going to skip adding any variables, templates or files for now. We will move on to creating a playbook which will include this role.

Creating Our Playbook:

Now that we have created our role to update packages, we will have to create a new playbook which will include this role in it.

- hosts: something
  become: yes
      - /full_path_to_role/galaxy/apt_update

Note that this playbook can be anywhere on our system and does not necessarily have to be in the same directory where our role is situated.

Running Our Playbook:

We have now created our playbook and also included the role we made into this. Now, all we have to do is to run this playbook and the packages at our remote system will be updated which can be observed on our terminal.

ansible-playbook apt_update_playbook.yml


In conclusion, I would like to point out that Ansible roles are a great method of reusing our tasks and simplifying what might have been a very complex playbook. Clearly isolated directories for each part of the role help people to understand this process much easier. Thanks for reading this blog!