Grouping Tasks With Blocks
Every task in this course so far has stood on its own. block: groups several tasks together, letting them share a single when:, become, or other keyword — set once, applying to the whole group, instead of repeated on every task inside it.
What Is A block?
A block is used to group tasks. You write block as lists of tasks inside tasks key.
- name: Block Play
hosts: fedora
tasks:
- name: Setup Block
block:
- name: Task one
ansible.builtin.debug:
msg: "First task"
- name: Task two
ansible.builtin.debug:
msg: "Second task"On its own, this doesn’t behave differently from writing two separate tasks — the real value shows up the moment you attach a shared keyword to the block itself.
Applying when: Once, To Several Tasks
Recall the OS-conditional pattern from the tests and conditionals section — a when: repeated on every single task that needed it. block: lets you write that condition exactly once, covering every task inside:
- name: Block Play
hosts: servers
tasks:
- name: Debian-only setup steps
block:
- name: Step one
ansible.builtin.debug:
msg: "Debian step one"
- name: Step two
ansible.builtin.debug:
msg: "Debian step two"
when: ansible_facts['os_family'] == 'Debian'Both tasks only run on Debian-family hosts — one condition, applied once, instead of duplicated across every task that needed it.
Other Keywords That Apply The Same Way
become, tags, vars, and most other task-level keywords behave identically when set on a block — they apply to every task inside, and any individual task can still override the block’s value for itself if it genuinely needs something different:
tasks:
- name: Privileged setup
block:
- name: Step one
ansible.builtin.command: whoami
- name: Step two
ansible.builtin.command: id
become: trueA Realistic Example: Grouped Setup Steps
Combining several shared keywords on one block at once:
- name: Block Play
hosts: servers
tasks:
- name: Configure app on Debian hosts
block:
- name: Check config directory
ansible.builtin.command: test -d /etc/myapp
register: config_dir_check
failed_when: false
- name: Report status
ansible.builtin.debug:
msg: "Config directory exists: {{ config_dir_check.rc == 0 }}"
when: ansible_facts['os_family'] == 'Debian'
become: trueBoth tasks run with elevated privileges, and only on Debian-family hosts — each property stated exactly once.
A Gotcha: You Can’t loop: A Block Directly
Given the section you just finished, this is worth flagging clearly: block: does not support loop: the way an individual task does.
- name: Loop Block
hosts: servers
tasks:
- name: Try to loop a block (doesn't work this way)
block:
- name: Print item
ansible.builtin.debug:
msg: "{{ item }}"
loop:
- one
- twoYou will get error:
[ERROR]: 'loop' is not a valid attribute for a BlockThere’s no way to repeat an entire block’s worth of tasks per list item just by attaching loop: to the block itself. If you genuinely need that, the answer is the exact nested-loop pattern from the loops section — move the tasks into their own file, and loop the include_tasks call that includes them:
- name: Loop Block
hosts: fedora
tasks:
- name: Loop over the group of tasks
ansible.builtin.include_tasks: task_block.yaml
loop: ["alice", "bob"]- name: Execute tasks with elevated privileges
become: true
block:
- name: Some privileged task1
ansible.builtin.debug:
msg: First
- name: Some privileged task2
ansible.builtin.debug:
msg: "I am {{ item }}"If the included file’s tasks need their own shared when: or become, wrap them in a block: inside that file too — combining both techniques, exactly the way you’d expect once you know neither one blocks the other.
Best Practices
- Use
block:to applywhen:/become:/vars:once, rather than repeating the same keyword across every task in a related group. - Name the block itself, and still name every task inside it — grouping doesn’t reduce the value of clear, individual task names in the output.
- Reach for
include_tasksplusloop:, not aloop:on the block itself, any time you need to repeat an entire group of tasks per item — the block-levelloop:you might expect to exist simply doesn’t.