Skip to content

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.

basic_block.yaml
- 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:

os_block.yaml
- 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: true

A Realistic Example: Grouped Setup Steps

Combining several shared keywords on one block at once:

configure_app.yaml
- 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: true

Both 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
        - two

You will get error:

[ERROR]: 'loop' is not a valid attribute for a Block

There’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:

main.yaml
- name: Loop Block
  hosts: fedora
  tasks:
    - name: Loop over the group of tasks
      ansible.builtin.include_tasks: task_block.yaml
      loop: ["alice", "bob"]
task_block.yaml
- 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 apply when:/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_tasks plus loop:, not a loop: on the block itself, any time you need to repeat an entire group of tasks per item — the block-level loop: you might expect to exist simply doesn’t.
Last updated on