Ansible: Key Differences Between include_tasks vs import_tasks and When to Use Each


2 views

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 with when 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