In an Ansible role created by `ansible-galaxy init`, what does each standard directory (tasks, handlers, defaults, vars, files, templates, meta) hold, and which files does Ansible load automatically?
answer
- convention over configuration on disk
- every subdirectory is loaded by main.yml
- files/ and templates/ are search paths
- defaults low precedence, vars high
- meta holds dependencies plus Galaxy info
basics
~10 sAn Ansible role is a fixed directory tree - tasks/, handlers/, defaults/, vars/, files/, templates/, meta/. Ansible auto-loads main.yml from each of those directories, and resolves copy and template sources against files/ and templates/.
solid answer
~40 sA role is a convention-over-configuration directory layout, and the convention is that Ansible looks for `main.yml` in each subdirectory. `tasks/main.yml` is the entry point that runs when the role is applied. `handlers/main.yml` defines the role's handlers. `defaults/main.yml` holds overridable default variables and `vars/main.yml` holds high-precedence role variables. `files/` holds static files that the `copy` module finds by bare filename, `templates/` holds Jinja2 templates that the `template` module finds the same way - both are searched relative to the role, which is why `src: nginx.conf` works with no path. `meta/main.yml` carries role dependencies and the Galaxy metadata (author, license, supported platforms). `ansible-galaxy init <name>` scaffolds all of it plus a README and a `tests/` directory, so you get the layout for free rather than remembering it.
code
bash · 2 linesansible-galaxy init nginx
find nginx -maxdepth 2 -not -path '*/.git*' | sortgo deeper
Be able to name the directories and say what each holds, and state that tasks/main.yml is the entry point Ansible runs. Mention that copy finds files in files/ and template finds them in templates/.
Explain that the layout is a loading convention, not syntax: Ansible looks for main.yml in each known subdirectory and skips the ones that do not exist. Be ready to say how you split a large role across several task files.
Show how the layout enables reuse in practice - a role with no absolute paths can be versioned, published and consumed unchanged by another team. Talk about what you keep out of a role to stop it becoming a second playbook.
Own the standard: what a role in your estate must include before it is shareable (README, defaults for every knob, declared platforms, tests) and whether custom plugins ship inside roles or get promoted into a collection.
## What a role actually is A role is not a language feature with its own syntax - it is a **directory layout plus a loading convention**. When you apply a role, Ansible walks a known set of subdirectories and loads `main.yml` from each one it finds. Nothing else about the role is declared anywhere; the filesystem is the interface. That is why two roles written by two different teams still compose: they agree on where things live. ## The directories ``` nginx/ tasks/main.yml # the entry point - what the role does handlers/main.yml # handlers the role's tasks can notify defaults/main.yml # default variables, lowest precedence vars/main.yml # role variables, high precedence files/ # static files, copied verbatim templates/ # Jinja2 templates, rendered per host meta/main.yml # dependencies + Galaxy metadata README.md ``` **tasks/** - `tasks/main.yml` is the only automatic entry point. Larger roles split work into `install.yml`, `configure.yml` and so on, and `tasks/main.yml` pulls them in with `ansible.builtin.import_tasks` or `ansible.builtin.include_tasks`; inside a role those filenames resolve relative to `tasks/`, so `import_tasks: install.yml` is enough. Callers can also select an alternative entry point with the `tasks_from` option of `include_role`/`import_role`. **handlers/** - `handlers/main.yml` is loaded whenever the role is applied, so the role's own tasks (and, once the role has run, later tasks in the play) can notify them by name. **defaults/** and **vars/** - both are automatically loaded variable files, and the *only* difference that matters is precedence. Role defaults sit at the very bottom of Ansible's variable precedence ladder, just above command-line connection settings, so essentially anything a user sets wins over them. Role vars sit far higher - above inventory `group_vars`/`host_vars` and above play `vars` - and are beaten only by task-level vars, role parameters, `set_fact`, and `-e` extra vars. So `defaults/` is the role's public knob panel and `vars/` is its internal constants drawer. **files/** and **templates/** - these are search paths, not just folders. Inside a role, modules that take a `src` resolve it relative to the role: `ansible.builtin.copy` looks in `files/`, and `ansible.builtin.template` looks in `templates/`. This is what makes a role relocatable - no absolute paths anywhere: ```yaml - name: Install the config ansible.builtin.template: src: nginx.conf.j2 # found at nginx/templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf ``` **meta/** - `meta/main.yml` carries two unrelated things: a `dependencies:` list of roles that must run before this one, and `galaxy_info` (author, description, license, `min_ansible_version`, supported `platforms`, `galaxy_tags`) which Galaxy reads when the role is published and which humans read to know whether the role targets their OS. Scaffolds from `ansible-galaxy init` also include a `tests/` directory with a throwaway inventory and playbook. Roles may additionally ship code in `library/` (custom modules), `module_utils/`, `filter_plugins/` and `lookup_plugins/`, though modern practice is to ship plugins in a collection instead. ## Why the layout is the interview question Because the layout *is* the reuse story. A playbook that has grown to eight hundred lines cannot be shared, versioned or tested; the same content split into roles can be published to Galaxy, pinned by version, and dropped into another team's repository without editing a path. Interviewers ask it as a screening question: if you cannot say what `defaults/` is for, you have used roles someone else wrote but never authored one. ## Common traps Creating a top-level `main.yml` in the role root does nothing - the loader only looks inside the known subdirectories. Putting a Jinja2 template in `files/` means `template` will not find it by bare name. Assuming every directory must exist is also wrong: a role with only `tasks/main.yml` is perfectly valid, and empty directories are simply skipped. Finally, `ansible-galaxy init` creates the skeleton but no content - it does not inspect anything or generate tasks for you.
- If a role's work is too big for one file, how do you split tasks/main.yml without breaking the role?Add more task files under `tasks/` and pull them in from `tasks/main.yml` with `ansible.builtin.import_tasks: install.yml` or `include_tasks:`. Inside a role those names resolve relative to `tasks/`, so no paths are needed and the role stays relocatable. A caller who wants a different entry point can pass `tasks_from: configure.yml` to `include_role` or `import_role`.
- Does every one of those directories have to exist for the role to work?No. Ansible simply skips subdirectories that are absent, so a role consisting of nothing but `tasks/main.yml` is valid and common. `ansible-galaxy init` creates the full skeleton for convenience, and many teams delete the empty parts before committing so readers are not misled into thinking there is content there.
- What goes in meta/main.yml besides dependencies?The `galaxy_info` block: author, description, `license`, `min_ansible_version`, the `platforms` list of OS/version pairs the role supports, and `galaxy_tags`. Galaxy renders it on the role's page and uses it for search, and it is how a consumer decides whether the role targets their distribution before they install it.
saying these in an interview costs you the question
- Says a role needs a main.yml at its root directory
- Puts Jinja2 templates in files/ instead of templates/
- Thinks ansible-galaxy init generates working tasks
- Claims all seven directories are mandatory
- Cannot name any difference between defaults/ and vars/