Ansible Tags: Run Specific Tasks and Roles Selectively (Guide)
By Luca Berton · Published 2024-01-01 · Category: installation
Complete guide to Ansible tags. Run specific tasks with --tags, skip tasks with --skip-tags, tag roles and includes, use special tags (always, never).
Tags let you run or skip specific parts of a playbook. Instead of running everything, use --tags deploy to only run deployment tasks, or --skip-tags debug to skip debugging output. Essential for large playbooks and iterative development.
Basic Usage
Tag Tasks
tasks:
- name: Install packages
ansible.builtin.package:
name: nginx
state: present
tags: install
- name: Deploy configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags: configure
- name: Start service
ansible.builtin.systemd:
name: nginx
state: started
enabled: true
tags: service
Run with Tags
# Run only install tasks
ansible-playbook site.yml --tags install
# Run install and configure tasks
ansible-playbook site.yml --tags "install,configure"
# Skip service tasks
ansible-playbook site.yml --skip-tags service
# List all tags in a playbook
ansible-playbook site.yml --list-tags
# List tasks that would run
ansible-playbook site.yml --tags deploy --list-tasks
See also: Ansible Playbook Structure: Anatomy, Best Practices & Examples (2026)
Multiple Tags Per Task
- name: Deploy app config
ansible.builtin.template:
src: app.conf.j2
dest: /etc/app/config.yml
tags:
- configure
- deploy
- app
# Runs if ANY of its tags match --tags
Special Tags
always — Runs Unless Explicitly Skipped
- name: Gather facts (always runs)
ansible.builtin.setup:
tags: always
- name: Show deployment info (always runs)
ansible.builtin.debug:
msg: "Deploying to {{ inventory_hostname }}"
tags: always
- name: Install packages (only with --tags install)
ansible.builtin.package:
name: nginx
state: present
tags: install
# "always" tasks run even with --tags install
ansible-playbook site.yml --tags install
# Runs: Gather facts + Show deployment info + Install packages
# Skip "always" tasks explicitly
ansible-playbook site.yml --tags install --skip-tags always
never — Only Runs When Explicitly Requested
- name: Dangerous cleanup (never runs by default)
ansible.builtin.file:
path: /var/log/app
state: absent
tags:
- never
- cleanup
- name: Debug dump (never runs by default)
ansible.builtin.debug:
var: hostvars[inventory_hostname]
tags:
- never
- debug
# Won't run unless you explicitly request it
ansible-playbook site.yml # Does NOT run cleanup
ansible-playbook site.yml --tags cleanup # DOES run cleanup
See also: Ansible Variable Precedence: Complete Order of Priority (2026)
Tag Roles
# Tag entire role
- hosts: webservers
roles:
- role: common
tags: common
- role: nginx
tags:
- nginx
- webserver
- role: app
tags: app
# Only run the nginx role
ansible-playbook site.yml --tags nginx
Tag Includes and Imports
# Tags on import_tasks apply to ALL tasks in the file
- name: Import database tasks
ansible.builtin.import_tasks: database.yml
tags: database
# Every task in database.yml gets the "database" tag
# Tags on include_tasks apply to the include itself
- name: Include monitoring tasks
ansible.builtin.include_tasks: monitoring.yml
tags: monitoring
# The include is tagged, but tasks inside keep their own tags
See also: Ansible block, rescue, always: Error Handling Complete Guide (2026)
Tag Blocks
- name: Database setup
tags: database
block:
- name: Install PostgreSQL
ansible.builtin.package:
name: postgresql
state: present
- name: Start PostgreSQL
ansible.builtin.systemd:
name: postgresql
state: started
- name: Create database
community.postgresql.postgresql_db:
name: myapp
Real-World Tag Strategy
---
- hosts: all
become: true
tasks:
# Phase 1: Base system
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
tags: [base, packages]
- name: Install base packages
ansible.builtin.package:
name: "{{ base_packages }}"
state: present
tags: [base, packages]
# Phase 2: Security
- name: Configure firewall
ansible.builtin.template:
src: iptables.j2
dest: /etc/iptables/rules.v4
tags: [security, firewall]
notify: reload firewall
- name: Configure SSH
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
tags: [security, ssh]
notify: restart sshd
# Phase 3: Application
- name: Deploy application
ansible.builtin.git:
repo: "{{ app_repo }}"
dest: "{{ app_dir }}"
version: "{{ app_version }}"
tags: [deploy, app]
- name: Install dependencies
ansible.builtin.pip:
requirements: "{{ app_dir }}/requirements.txt"
virtualenv: "{{ app_dir }}/venv"
tags: [deploy, app, deps]
- name: Restart application
ansible.builtin.systemd:
name: myapp
state: restarted
tags: [deploy, app, restart]
# Diagnostics
- name: Show system status
ansible.builtin.command: systemctl status myapp
tags: [never, status]
changed_when: false
handlers:
- name: reload firewall
ansible.builtin.command: iptables-restore < /etc/iptables/rules.v4
- name: restart sshd
ansible.builtin.systemd:
name: sshd
state: restarted
# Full run
ansible-playbook site.yml
# Just deploy the app
ansible-playbook site.yml --tags deploy
# Security hardening only
ansible-playbook site.yml --tags security
# Quick check on app status
ansible-playbook site.yml --tags status
# Everything except firewall changes
ansible-playbook site.yml --skip-tags firewall
FAQ
How do Ansible tags work?
Tags are labels on tasks. When you run --tags deploy, only tasks tagged deploy execute (plus always tasks). When you run --skip-tags debug, all tasks run except those tagged debug.
What is the difference between always and never tags?
always tasks run regardless of --tags filtering (unless explicitly skipped with --skip-tags always). never tasks never run unless explicitly requested with --tags .
Can a task have multiple tags?
Yes, use a list: tags: [deploy, app, v2]. The task runs if ANY of its tags match --tags. All tags must be in --skip-tags to skip it.
How do tags work with roles?
Tagging a role applies the tag to ALL tasks in that role. You can also tag individual tasks within a role normally. Both approaches work together.
Should I tag every task?
No — tag groups of related tasks for logical operations (deploy, configure, security). Over-tagging makes playbooks harder to read. Use tags for tasks you'll want to run independently.
Conclusion
•--tags deploy — Run only tagged tasks
• --skip-tags debug — Run everything except tagged tasks
• always — Tasks that always run (gather facts, logging)
• never — Tasks that only run on explicit request (cleanup, debug)
• Tag roles and blocks — Apply tags to groups of tasks
• --list-tags — See all available tags before running
Related Articles
• Ansible Playbook Structure & Best Practices • Ansible import_tasks vs include_tasks • Ansible Check Mode / Dry RunSee also
• Ansible Tags: Run Specific Tasks in Playbooks (Complete Guide)Category: installation