Skip to content

import_playbook


The static-vs-dynamic split from the previous chapter isn’t unique to tasks — it extends both upward, to combining whole playbooks together, and downward, into roles. This chapter covers both, plus one asymmetry worth knowing: at the playbook level, only the static half of the pair actually exists.

import_playbook: Combining Multiple Playbooks Into One Run

import_playbook combines several playbook files into a single run — used at the top level of a playbook file, not inside a play’s tasks: list, and each imported file contains a full play of its own (hosts:, tasks:, everything), not just a bare list of tasks.

site.yaml
- import_playbook: webservers.yaml
- import_playbook: databases.yaml
webservers.yaml
- name: Configure web servers
  hosts: webservers
  tasks:
    - name: Example task
      ansible.builtin.debug:
        msg: "Configuring web servers"
databases.yaml
- name: Configure databases
  hosts: databases
  tasks:
    - name: Example task
      ansible.builtin.debug:
        msg: "Configuring web servers"

This is how you’d maintain separate playbook files per concern or group — webservers.yaml, databases.yaml — and combine them into one overall entry point, commonly named something like site.yaml, run as a single ansible-playbook invocation.

site.yaml can also have own set of target hosts and tasks afterwards:

site.yaml
- import_playbook: webservers.yaml
- import_playbook: databases.yaml
- name: Play run in localhost
  hosts: localhost
  tasks:
    - name: whoami_local
      ansible.builtin.command:
        cmd: whoami
      register: whoami_localhost

    - name: whoami_localhost check
      ansible.builtin.debug:
        var: whoami_localhost.stdout

tasks listed in site.yaml runs on localhost (because of hosts: localhost) whereas tasks on imported playbooks runs on whatever hosts are implied there. For more information, you can run ansible-playbook site.yaml --list-tasks.

Why There’s No include_playbook

Worth stating directly, since it’s a reasonable assumption to make otherwise: there is no dynamic equivalent at the playbook level. import_playbook is always resolved statically, at parse time, with no runtime alternative available at all. Unlike tasks, where you genuinely choose between static and dynamic based on what you need, combining playbooks only ever has one option.

A First Look At Roles: import_role And include_role

Roles get a full section of their own later in this course — this is just enough to recognize the syntax now, since it follows the exact same naming convention already established:

- name: Import a role statically
  ansible.builtin.import_role:
    name: my_role
- name: Include a role dynamically
  ansible.builtin.include_role:
    name: my_role

The Same Static/Dynamic Rule Applies

Identical reasoning to Chapter 1, just one level up: import_role’s role name has to be fixed and known in advance, while include_role’s can depend on runtime data:

- name: Include a role determined at runtime
  ansible.builtin.include_role:
    name: "{{ ansible_facts['os_family'] | lower }}_setup"

This works with include_role for exactly the reason include_tasks worked in the previous chapter’s example — and would fail with import_role for exactly the same reason import_tasks did.

Best Practices

  • Use import_playbook to compose multiple playbook files into one overall run — there’s no dynamic alternative to weigh against, so this is simply the way it’s done.
  • Recognize import_role/include_role now, even without full role-authoring knowledge yet — the static/dynamic distinction transfers directly from what you already know about tasks.
  • Default to include_role when a role’s name might vary at runtime, following the exact same reasoning as include_tasks.
Last updated on