As your Ansible automation grows, managing everything inside a single playbook can get overwhelming. That’s where importing or including playbooks comes in handy.
With import_playbook and include_tasks, you can break large automation scripts into smaller, reusable components—making your playbooks easier to read, debug, and scale.
In this guide, you’ll learn how to use both methods effectively with real-world examples.
Table of Contents
What is the Difference Between import_playbook and include_tasks?
Let’s start by understanding the key differences:
Feature | import_playbook | include_tasks |
---|---|---|
Type | Static inclusion | Dynamic inclusion |
Use Case | Reuse entire playbooks | Include tasks based on conditions |
Evaluated | Before playbook execution | During playbook execution |
Use Inside Tasks | ❌ Not supported | ✅ Yes |
When to Use Which
✅ Use import_playbook
when:
You want to reuse full playbooks across projects.
You don’t need dynamic conditions.
✅ Use include_tasks
when:
You want to conditionally run different tasks based on variables or facts.
You want to modularize logic inside a playbook dynamically.
Basic Syntax
Here’s how to use import_playbook and include_tasks in Ansible:
Using import_playbook
# main_playbook.yml
- import_playbook: playbooks/webserver_setup.yml
Using include_tasks
# main_playbook.yml
- include_tasks: tasks/configure_firewall.yml
The main difference is that import_playbook is processed before execution, while include_tasks is processed dynamically during execution.
Example 1: Using import_playbook
Let’s look at a scenario where we use import_playbook to include another playbook.
Here is a directory structure of the Ansible project:
my_ansible_project/
├── main_playbook.yml
└── playbooks/
└── webserver_setup.yml
Content of webserver_setup.yml
---
- name: Setup Web Server
hosts: webservers
tasks:
- name: Install NGINX
ansible.builtin.yum:
name: nginx
state: present
- name: Start and Enable NGINX
ansible.builtin.systemd:
name: nginx
state: started
enabled: true
Content of main_playbook.yml
---
- import_playbook: playbooks/webserver_setup.yml
Now, run the main playbook.
# ansible-playbook main_playbook.yml
Output:
PLAY [Setup Web Server] ********************************************************
TASK [Install NGINX] ***********************************************************
changed: [webserver1]
TASK [Start and Enable NGINX] **************************************************
changed: [webserver1]
PLAY RECAP *********************************************************************
webserver1 : ok=2 changed=2 unreachable=0 failed=0
In this example, we used import_playbook to include the webserver_setup.yml playbook. The tasks from the imported playbook are executed as if they were written directly in the main playbook.
Example 2: Using include_tasks
Now, let’s see an example of using include_tasks to dynamically include tasks based on conditions.
Here is a directory structure:
my_ansible_project/
├── main_playbook.yml
└── tasks/
├── setup_dev.yml
└── setup_prod.yml
Content of setup_dev.yml
---
- name: Install Development Tools
ansible.builtin.yum:
name: git
state: present
Content of setup_prod.yml
---
- name: Install Production Monitoring Tools
ansible.builtin.yum:
name: htop
state: present
Content of main_playbook.yml
---
- hosts: all
tasks:
- include_tasks: tasks/setup_dev.yml
when: env == 'dev'
- include_tasks: tasks/setup_prod.yml
when: env == 'prod'
Now, run the main playbook with an extra variable (env=dev).
# ansible-playbook main_playbook.yml -e "env=dev"
Output:
PLAY [all] *********************************************************************
TASK [Install Development Tools] ***********************************************
changed: [host1]
PLAY RECAP *********************************************************************
host1 : ok=1 changed=1 unreachable=0 failed=0
In this example, include_tasks is used to dynamically include either setup_dev.yml or setup_prod.yml based on the value of the env variable. This allows for conditional task execution, providing flexibility in how tasks are executed.
Advanced Usage: Conditional Task Inclusion
You can use include_tasks with conditions based on facts gathered during the playbook run.
The following example executes tasks conditionally using the when statement:
---
- hosts: all
tasks:
- include_tasks: tasks/setup_ubuntu.yml
when: ansible_os_family == 'Debian'
- include_tasks: tasks/setup_centos.yml
when: ansible_os_family == 'RedHat'
This setup dynamically includes task files based on the detected OS family (Debian or RedHat). It helps in executing platform-specific tasks.
Common Pitfalls and Tips
import_playbook
must be at the top level, not undertasks:
Ensure files exist and paths are correct relative to the calling playbook.
Use
include_tasks
for conditional logic;import_tasks
behaves like a static version but is rarely used now.
Conclusion
Organizing large Ansible projects becomes easier with import_playbook
and include_tasks
. Use these tools to:
Reuse logic across environments
Apply OS-specific configurations
Write cleaner, more modular playbooks
With a bit of planning, your automation scripts can stay clean, efficient, and scalable.
FAQs
1. Can I use conditions with import_playbook?
No, conditions (like when) are not supported with import_playbook. Use include_tasks if you need conditional logic.
2. How do I include tasks from another playbook file?
Use import_playbook: filename.yml in your main playbook or include_tasks: filename.yml within a task block.
3. Why should I use include_tasks instead of copying tasks directly?
Using include_tasks helps keep your playbooks modular, making them easier to read, maintain, and reuse across multiple playbooks.