Skip to content

Ansible Role Directory Structure


This chapter covers the biggest conceptual shift in this entire course: files that load themselves, purely by being named and placed correctly, with nothing anywhere explicitly pointing at them.

The Standard Role Layout

roles/
  myapp/
    tasks/
      main.yml
    handlers/
      main.yml
    templates/
      app.conf.j2
    files/
      static_file.txt
    vars/
      main.yml
    defaults/
      main.yml
    meta/
      main.yml

tasks/main.yml: The Role’s Entry Point

The role’s actual task list — exactly the same task syntax used throughout this entire course, just living in this specific file instead of directly inside a play:

roles/myapp/tasks/main.yml
- name: Install myapp package
  ansible.builtin.package:
    name: myapp
    state: present

- name: Deploy config
  ansible.builtin.template:
    src: app.conf.j2
    dest: /etc/myapp/app.conf
  notify: Restart myapp

handlers/main.yml: Automatically Available Handlers

Any handler defined here becomes available to be notified from within the role’s own tasks automatically — no special linking required:

roles/myapp/handlers/main.yml
- name: Restart myapp
  ansible.builtin.systemd:
    name: myapp
    state: restarted

templates/ And files/: No src: Path Needed

A genuinely convenient shift from everything covered so far: when a task inside a role references template: src: app.conf.j2, Ansible automatically looks inside this role’s own templates/ directory first — no relative or absolute path needed, unlike the careful path resolution this course covered for lookups and templates used directly in a standalone playbook. The same automatic resolution applies to files/ for copy’s src:.

vars/main.yml And defaults/main.yml: Two Kinds Of Variables

Both hold variables, but with a real, important precedence difference between them — covered in full in the next chapter. For now, just note their location: vars/main.yml and defaults/main.yml, both loaded automatically the same way tasks/main.yml is.

meta/main.yml: Role Metadata And Dependencies

Holds information about the role itself, and — genuinely more important — declared dependencies on other roles. Covered fully later in this section; for now, just its location: meta/main.yml.

The Big Shift: main.yml Is Loaded Automatically

This is worth sitting with directly, since it’s a real departure from everything this course has built up until now. Every single file reference covered so far — vars_files, import_tasks, a template’s src:, a lookup’s file path — required explicitly naming or pointing at that file, somewhere. Inside a role, a file named exactly main.yml, sitting in one of these standard directories, is loaded automatically, purely by its name and location. There’s no import_tasks: tasks/main.yml written anywhere inside the role, no vars_files: pointing at vars/main.yml — simply placing a correctly-named file in the correct directory is enough.

A Realistic Skeleton

Bringing tasks/, handlers/, and templates/ together into one coherent role, with vars/, defaults/, and meta/ left minimal for now — full treatment of each comes in upcoming chapters:

roles/
  myapp/
    tasks/
      main.yml        # Install package, deploy template, notify handler
    handlers/
      main.yml         # Restart myapp
    templates/
      app.conf.j2      # The actual config template
    defaults/
      main.yml         # (covered next chapter)
    vars/
      main.yml         # (covered next chapter)
    meta/
      main.yml          # (covered later in this section)

Best Practices

  • Always name the file main.yml inside each of these standard subdirectories — this exact name is what makes automatic loading work; anything else is silently never picked up.
  • Keep a role focused on one coherent piece of functionality, like “deploy myapp,” rather than a grab-bag of loosely related tasks.
  • Rely on the automatic templates//files/ resolution — don’t write full paths to these locations from within a role’s own tasks; the whole point is that you don’t have to.
Last updated on