Tags & Limits
What are Tags? Tags allow you to selectively execute specific portions of a playbook rather than running everything. They provide fine-grained control over which tasks run, making it easy to run maintenance operations, deploy specific components, or skip certain tasks without modifying playbook code.
Understanding Tags
Why Use Tags?
Tags solve common automation challenges:
- Selective Execution: Run only database tasks in a full-stack deployment
- Skip Operations: Bypass slow or unnecessary tasks during development
- Maintenance Windows: Run only backup or monitoring tasks
- Development Workflows: Test specific components without full deployment
- Conditional Runs: Execute tasks based on operational needs
Tag Workflow
Using tags is a two-step process:
- Add Tags: Apply tags to tasks, blocks, plays, roles, or imports
- Select Tags: Use command-line options to run or skip tagged tasks
Adding Tags to Playbooks
Tagging Individual Tasks
Apply tags directly to tasks:
---
- name: Deploy web application
hosts: webservers
tasks:
- name: Install packages
ansible.builtin.yum:
name:
- httpd
- php
- php-mysql
state: present
tags:
- packages
- install
- name: Copy configuration files
ansible.builtin.copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
tags:
- config
- configuration
- name: Start Apache service
ansible.builtin.service:
name: httpd
state: started
enabled: true
tags:
- service
- httpd
- name: Deploy application code
ansible.builtin.git:
repo: https://github.com/company/webapp.git
dest: /var/www/html
version: main
tags:
- deploy
- application
Tagging Blocks
Apply tags to multiple tasks at once:
---
- name: Database setup
hosts: databases
tasks:
- name: Database configuration
tags:
- database
- db
block:
- name: Install PostgreSQL
ansible.builtin.yum:
name: postgresql-server
state: present
- name: Initialize database
ansible.builtin.command: postgresql-setup initdb
args:
creates: /var/lib/pgsql/data/PG_VERSION
- name: Configure authentication
ansible.builtin.copy:
src: pg_hba.conf
dest: /var/lib/pgsql/data/pg_hba.conf
- name: Start PostgreSQL
ansible.builtin.service:
name: postgresql
state: started
enabled: true
Tagging Plays
Apply tags to entire plays:
---
- name: Web server setup
hosts: webservers
tags:
- webserver
- web
tasks:
- name: Install nginx
ansible.builtin.yum:
name: nginx
state: present
- name: Configure nginx
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: Application deployment
hosts: webservers
tags:
- application
- deploy
tasks:
- name: Clone repository
ansible.builtin.git:
repo: https://github.com/company/app.git
dest: /opt/app
- name: Install dependencies
ansible.builtin.pip:
requirements: /opt/app/requirements.txt
Tagging Roles
Apply tags to imported or included roles:
---
- name: Full infrastructure setup
hosts: all
roles:
- role: common
tags:
- common
- base
- role: security
tags:
- security
- hardening
- role: monitoring
tags:
- monitoring
- observability
- role: webserver
tags:
- webserver
- nginx
Tagging Imports and Includes
---
- name: Complex deployment
hosts: all
tasks:
- name: Common tasks
ansible.builtin.import_tasks: common.yml
tags:
- common
- always
- name: Database tasks
ansible.builtin.import_tasks: database.yml
tags:
- database
- db
- name: Dynamic web configuration
ansible.builtin.include_tasks: "{{ item }}"
loop:
- web_config.yml
- ssl_setup.yml
tags:
- web
- config
Special Tags
always Tag
Tasks tagged with always run unless explicitly skipped:
---
- name: Application deployment
hosts: webservers
tasks:
- name: Check prerequisites
ansible.builtin.command: which python3
tags:
- always
changed_when: false
- name: Install application
ansible.builtin.yum:
name: myapp
state: present
tags:
- install
- name: Send notification
ansible.builtin.uri:
url: https://hooks.slack.com/services/YOUR/WEBHOOK
method: POST
body_format: json
body:
text: "Deployment completed"
tags:
- always
delegate_to: localhost
Run playbook skipping non-tagged tasks:
# Only 'always' tasks run ansible-playbook site.yml --tags never # Skip 'always' tasks ansible-playbook site.yml --skip-tags always
never Tag
Tasks tagged with never only run when explicitly requested:
---
- name: Database management
hosts: databases
tasks:
- name: Regular backup
ansible.builtin.command: pg_dump mydb > /backup/mydb.sql
tags:
- backup
- name: DANGEROUS - Drop database
community.postgresql.postgresql_db:
name: mydb
state: absent
tags:
- never
- destroy
- name: DANGEROUS - Delete all data
ansible.builtin.file:
path: /var/lib/postgresql/data
state: absent
tags:
- never
- destroy
- purge
Explicitly run never-tagged tasks:
# Must explicitly request 'never' tasks ansible-playbook database.yml --tags destroy
tagged and untagged
Built-in special tags for filtering:
# Run only tasks with at least one tag ansible-playbook site.yml --tags tagged # Run only tasks without any tags ansible-playbook site.yml --tags untagged
all Tag
Default behavior - runs all tasks except those tagged never:
# Equivalent commands (default behavior) ansible-playbook site.yml ansible-playbook site.yml --tags all
Running Tagged Tasks
Run Specific Tags
# Run tasks with single tag ansible-playbook site.yml --tags configuration # Run tasks with multiple tags (OR logic) ansible-playbook site.yml --tags "packages,config" # Tasks with 'packages' OR 'config' tag will run
Skip Specific Tags
# Skip tasks with specific tag ansible-playbook site.yml --skip-tags testing # Skip multiple tags ansible-playbook site.yml --skip-tags "backup,monitoring"
Combine Tags and Skip-Tags
# Run web tasks but skip deployment ansible-playbook site.yml --tags web --skip-tags deploy # Note: skip-tags takes precedence over tags
Tag Precedence: When both
--tags and --skip-tags are specified, skip-tags always takes precedence. If a task matches both, it will be skipped.
Listing Tags
View All Available Tags
# List all tags in playbook ansible-playbook site.yml --list-tags # Output example: # playbook: site.yml # # play #1 (webservers): Deploy web application # TAGS: [web, webserver] # # play #2 (databases): Database setup # TAGS: [database, db] # # TASK TAGS: [application, backup, config, database, db, # deploy, install, packages, service, web, webserver]
Preview Tagged Tasks
# List tasks that would run with specific tags ansible-playbook site.yml --tags config --list-tasks # Output shows which tasks will execute: # playbook: site.yml # # play #1 (webservers): Deploy web application TAGS: [web] # tasks: # Copy configuration files TAGS: [config, configuration] # # play #2 (databases): Database setup TAGS: [database] # tasks: # Configure authentication TAGS: [config, database]
Limiting Execution
Limit by Host Pattern
Combine tags with host limits for precise control:
# Run config tasks only on web01 ansible-playbook site.yml --tags config --limit web01 # Run database tasks on db servers in production ansible-playbook site.yml --tags database --limit "databases:&production" # Run on all except one host ansible-playbook site.yml --limit "all:!problematic-host" # Run on hosts matching pattern ansible-playbook site.yml --limit "web*.example.com"
Limit by Group
# Run only on webservers group ansible-playbook site.yml --limit webservers # Run on multiple groups ansible-playbook site.yml --limit "webservers:databases" # Intersection of groups (hosts in both) ansible-playbook site.yml --limit "webservers:&production"
Limit by Failed Hosts
# First run that might fail ansible-playbook site.yml # Creates retry file: site.retry with failed hosts # Retry only failed hosts ansible-playbook site.yml --limit @site.retry
Tag Inheritance
How Tags Cascade
Tags applied at higher levels automatically cascade to child elements:
---
- name: Infrastructure setup
hosts: all
tags:
- infrastructure # Applies to all tasks in this play
tasks:
- name: Update system
ansible.builtin.yum:
name: "*"
state: latest
# This task has 'infrastructure' tag automatically
- name: Install security tools
ansible.builtin.yum:
name: aide
state: present
tags:
- security # This task has both 'infrastructure' and 'security'
Block Tag Inheritance
---
- name: Web configuration
hosts: webservers
tasks:
- name: SSL setup
tags:
- ssl
- security
block:
- name: Install mod_ssl
ansible.builtin.yum:
name: mod_ssl
state: present
# Inherits: ssl, security
- name: Generate certificate
ansible.builtin.command: openssl req -new -x509 -days 365 -nodes...
tags:
- certificates # Has: ssl, security, certificates
args:
creates: /etc/pki/tls/certs/localhost.crt
Role Tag Inheritance
---
- name: Apply roles
hosts: all
roles:
- role: common
tags:
- base
# All tasks in 'common' role inherit 'base' tag
- role: apache
tags:
- webserver
- apache
# All tasks in 'apache' role inherit both tags
Advanced Tag Patterns
Maintenance Tasks Pattern
---
- name: Application lifecycle
hosts: webservers
tasks:
# Normal operations
- name: Deploy application
ansible.builtin.copy:
src: app.jar
dest: /opt/app/app.jar
tags:
- deploy
- application
# Maintenance operations (never run by default)
- name: Clear cache
ansible.builtin.file:
path: /var/cache/app
state: absent
tags:
- never
- maintenance
- cache
- name: Rotate logs
ansible.builtin.command: logrotate -f /etc/logrotate.d/app
tags:
- never
- maintenance
- logs
- name: Vacuum database
ansible.builtin.command: vacuumdb --all
tags:
- never
- maintenance
- database
# Normal deployment (cache/logs/vacuum not run)
# ansible-playbook site.yml --tags deploy
# Maintenance mode (only maintenance tasks)
# ansible-playbook site.yml --tags maintenance
Environment-Specific Pattern
---
- name: Multi-environment deployment
hosts: all
tasks:
- name: Deploy to staging
ansible.builtin.git:
repo: https://github.com/company/app.git
dest: /opt/app
version: develop
tags:
- deploy
- staging
when: environment == "staging"
- name: Deploy to production
ansible.builtin.git:
repo: https://github.com/company/app.git
dest: /opt/app
version: main
tags:
- deploy
- production
when: environment == "production"
- name: Run database migrations
ansible.builtin.command: /opt/app/migrate.sh
tags:
- deploy
- database
- migrations
# Deploy to staging only
# ansible-playbook site.yml --tags staging -e environment=staging
# Deploy to production only
# ansible-playbook site.yml --tags production -e environment=production
Component-Based Pattern
---
- name: Full stack deployment
hosts: all
tasks:
# Frontend
- name: Build frontend
ansible.builtin.command: npm run build
args:
chdir: /opt/app/frontend
tags:
- frontend
- ui
- build
- name: Deploy frontend
ansible.builtin.copy:
src: /opt/app/frontend/dist/
dest: /var/www/html/
tags:
- frontend
- ui
- deploy
# Backend
- name: Build backend
ansible.builtin.command: mvn package
args:
chdir: /opt/app/backend
tags:
- backend
- api
- build
- name: Deploy backend
ansible.builtin.copy:
src: /opt/app/backend/target/app.jar
dest: /opt/services/app.jar
tags:
- backend
- api
- deploy
# Database
- name: Run migrations
ansible.builtin.command: flyway migrate
tags:
- database
- db
- migrations
# Deploy only frontend
# ansible-playbook site.yml --tags frontend
# Deploy only backend
# ansible-playbook site.yml --tags backend
# Deploy everything except database
# ansible-playbook site.yml --skip-tags database
Best Practices
Tagging Best Practices:
- Consistent Naming: Use clear, descriptive tag names across playbooks
- Multiple Tags: Apply multiple tags to tasks for flexible filtering
- Hierarchical Tags: Use general and specific tags (deploy, deploy-frontend)
- Document Tags: Maintain a list of available tags in README
- Use 'never' Carefully: Tag destructive operations with 'never'
- Test Tags: Use --list-tasks to verify tag behavior
- Avoid Over-Tagging: Don't tag every task; focus on logical groupings
- Combine with Limits: Use tags and limits together for precision
Common Tag Conventions
| Tag | Purpose | Example Usage |
|---|---|---|
always |
Tasks that always run | Prerequisites, notifications, logging |
never |
Dangerous/rare operations | Data deletion, service shutdown |
install |
Package installation | Installing software packages |
config |
Configuration changes | Updating config files |
deploy |
Application deployment | Deploying application code |
backup |
Backup operations | Database backups, file backups |
maintenance |
Maintenance tasks | Cache clearing, log rotation |
security |
Security operations | Firewall rules, SSL setup |
monitoring |
Monitoring setup | Metrics, alerts, dashboards |
testing |
Test execution | Running tests, validation |
Common Issues
Tags Not Working
If tags aren't filtering as expected:
- Use
--list-tagsto verify tags are applied - Check for typos in tag names
- Remember that
--skip-tagstakes precedence - Verify tasks aren't tagged with
always
Unexpected Tasks Running
If unwanted tasks execute:
- Check for
alwaystags on tasks - Verify tag inheritance from plays/blocks
- Use
--list-taskswith your tag selection - Remember imported tasks inherit tags
No Tasks Running
If no tasks execute:
- Verify tag names match exactly (case-sensitive)
- Check if all tasks are tagged
never - Ensure you're not skipping all tasks
- Verify limit pattern matches hosts
Next Steps
- Playbooks - Learn about playbook structure
- Roles - Organize tasks into reusable roles
- Advanced Playbooks - Advanced execution control
- Task Delegation - Control where tasks run
- Try the Playground - Practice using tags