Subtopic•Using Tags

What Are Tags

The previous module covered handlers — Ansible's reactive system for running tasks conditionally based on state changes. This module covers tags — Ansible's declarative system for selectively running parts of a playbook based on your command-line choice.

The Problem Tags Solve

A complete infrastructure provisioning playbook might have 200 tasks across dozens of roles: installing packages, configuring services, managing users, deploying applications, setting up monitoring. Running all 200 tasks every time you make a small config change is wasteful — it takes time, touches systems unnecessarily, and increases the risk of unintended changes.

Tags let you label tasks with meaningful categories. Then when you run the playbook, you specify which labels to include or exclude. Only the matching tasks run — the rest are skipped.

# Full provision: run everything
ansible-playbook site.yml

# Only run tasks tagged 'configure'
ansible-playbook site.yml --tags configure

# Run everything EXCEPT tasks tagged 'packages'
ansible-playbook site.yml --skip-tags packages

This makes your monolithic site.yml into a multitool — the same file serves as both the complete provisioner and the targeted update tool, depending on how you invoke it.


How Tags Work

Tags are arbitrary strings you assign to tasks, plays, roles, or blocks. Any number of tags can be assigned to any task. When you run --tags foo, only tasks that have foo in their tag list execute. When you run --skip-tags foo, only tasks that do NOT have foo in their tag list execute.

Tasks without any tags are always skipped when --tags is specified — they are not tagged, so they do not match. The exceptions are tasks tagged with the special always tag (covered later) which run regardless of --tags.


Tag Inheritance

Tags flow downward through the playbook structure. A tag applied to a block:, a roles: entry, or an import_tasks: directive is inherited by everything inside it:

# Tag applied to the entire role
roles:
  - role: webserver
    tags: [webserver, nginx]     # all tasks in the webserver role get these tags

# Tag applied to a block
- block:
    - name: Task A
    - name: Task B
    - name: Task C
  tags: [install]                # Task A, B, and C all get the 'install' tag

# Tag applied to an import_tasks
- ansible.builtin.import_tasks: configure.yml
  tags: [configure]              # all tasks in configure.yml get 'configure'

This inheritance is what makes tagging a play-level or role-level concern rather than something you put on every individual task.


Tags Do Not Apply to include_tasks the Same Way

There is an important distinction between import_tasks and include_tasks for tag inheritance:

import_tasks — Static inclusion. Tags applied to the import statement cascade to all tasks inside the included file. Running --tags configure will run matching tasks from the imported file.

include_tasks — Dynamic inclusion. Tags applied to include_tasks do NOT cascade to the tasks inside. The include_tasks task itself runs (if it matches the tag), but then all tasks inside are evaluated for their own tags independently. To make tags work with include_tasks, add tags to the tasks inside the included file.

For tag-driven selective execution, prefer import_tasks over include_tasks unless you specifically need dynamic filename resolution.

The next section covers the full syntax for applying tags to different structural levels of a playbook.

←Previous ModuleHandlers and Notifications