Grouping Tasks with block
Scenario: The same five-line when: condition is copy-pasted onto eleven consecutive tasks. Someone updates ten of them.
New words, in plain English
block- a group of tasks treated as one unit.- Inherited directives -
when,become,tagsand others set on a block apply to every task inside it. rescue- tasks that run only if something in the block failed.always- tasks that run afterwards regardless of the outcome.
A block groups tasks so that directives can be applied once to all of them. A when on the block applies to every task inside it; so do become, tags, ignore_errors and environment.
That alone removes a genuine class of bug - the copy-pasted condition that someone updates in ten places out of eleven - and it makes the structure of a play visible at a glance.
Blocks also introduce error handling, which Phase 4 covers in full: rescue runs if any task in the block fails, and always runs no matter what. Together they give Ansible try/catch/finally semantics, which is what makes safe deployment and reliable cleanup possible.
Two limits to know now. Blocks cannot be looped - loop on a block is not supported, and the workaround is include_tasks with a loop. And a task inside a block can still override an inherited directive with its own, which is occasionally what you want and occasionally a nasty surprise when reading someone else's play.
Analogy: A block is a bracket in arithmetic. Without it you have to repeat the multiplier against every term and hope you did not miss one. With it, the intent is written once and cannot drift apart.
A worked example
# Eleven copy-pasted conditions become one
- name: Database tier configuration
block:
- name: Install the client tooling
ansible.builtin.package:
name: postgresql-client
- name: Deploy the connection config
ansible.builtin.template:
src: pg.conf.j2
dest: /etc/app/pg.conf
- name: Ensure the service is running
ansible.builtin.service:
name: app-db-proxy
state: started
when: "'dbservers' in group_names" # applies to ALL THREE
tags: [database, config]
Blocks are also the natural unit for tagging. Tagging a block tags everything inside it, which keeps --tags config meaningful as a play grows, rather than depending on someone remembering to tag each new task individually.
Use them for genuine grouping, though, not as decoration. A block wrapped around a single task adds a level of indentation and nothing else. The value comes from shared directives or from rescue/always.
Tip: If you are about to paste the same when: onto a third consecutive task, stop and wrap them in a block instead.
Goal: Put this to work in the ansible-loops-conditionals lab. Open/labs/ansible, pickansible-loops-conditionals, and fix the real broken project - Ansible really does SSH into four managed hosts and converge them.