The fundamental difference between these modules lies in their processing time:
# import_tasks - Static inclusion (pre-processed during playbook parsing)
- import_tasks: setup_webserver.yml
# include_tasks - Dynamic inclusion (processed during runtime)
- include_tasks: configure_database.yml
Use import_tasks
when:
- Tasks need variable substitution during parsing
- Working with static configurations that won't change during execution
- You need to apply tags or conditionals to the entire import
- name: Import static server configuration
import_tasks: tasks/secure_ssh.yml
tags: security
when: ansible_os_family == 'RedHat'
include_tasks
becomes essential when:
- File names contain dynamic variables
- Task lists need runtime evaluation
- Using loop constructs with included files
- name: Include environment-specific tasks
include_tasks: "tasks/{{ environment }}/deploy.yml"
loop: [dev, staging, prod]
loop_control:
loop_var: environment
import_tasks
typically shows better performance for:
- Large playbooks with many includes
- Complex dependency chains
- Static infrastructure configurations
While include_tasks
excels in:
- Dynamic environments
- Cloud deployments with changing parameters
- Multi-phase execution workflows
- name: Import base configuration (static)
import_tasks: base_setup.yml
- name: Include dynamic components
include_tasks: "components/{{ item }}.yml"
with_items: "{{ components_to_install }}"
- Never use
import_tasks
withwhen
conditions that might change during execution - Avoid dynamic filenames with
import_tasks
- Remember that tags apply differently:
import_tasks
tags affect all contained tasks
In Ansible 2.4+, the deprecated include
module was replaced by two more specialized modules: include_tasks
and import_tasks
. While they appear similar at first glance, their execution behavior differs fundamentally.
import_tasks
follows static inclusion - tasks are processed during playbook parsing:
- name: Import static configuration tasks
import_tasks: setup_webserver.yml
include_tasks
uses dynamic inclusion - tasks are processed during runtime:
- name: Include conditional tasks
include_tasks: "{{ item }}"
loop:
- setup_db.yml
- configure_cache.yml
Use import_tasks when:
- Tasks need to be processed early in playbook parsing
- You're using tags or conditional statements at the playbook level
- Task files won't change during execution
Use include_tasks when:
- Tasks depend on runtime variables
- You need looping functionality
- Task files might be conditionally included
Example 1: Environment-specific configuration
- name: Import base configuration
import_tasks: common_config.yml
- name: Include environment-specific tasks
include_tasks: "{{ env_type }}_config.yml"
when: env_type is defined
Example 2: Looping through task files
- name: Install multiple components
include_tasks: install_component.yml
loop: "{{ components }}"
loop_control:
loop_var: component
import_tasks
generally has better performance for static includes as it's processed once during playbook initialization. include_tasks
incurs runtime overhead but provides greater flexibility.
- Avoid mixing tags between imported and included tasks - imported tasks inherit tags from the import statement
- Remember that variables in
import_tasks
are evaluated at parse time, not runtime - Dynamic includes can't use Ansible's
--start-at-task
flag