Handlers, loops & conditionals
React to change; repeat; branch.
A handler is a task that runs only when notified, and only once at the end of a play — the standard pattern for “restart the service if (and only if) its config changed.” A task that modifies a file calls notify; if that task reports changed, the named handler runs after all tasks complete. If nothing changed, the handler does not run, which keeps reloads from happening needlessly on every play.
tasks:- name: Deploy configansible.builtin.template: { src: app.conf.j2, dest: /etc/app/app.conf }notify: restart app # fires the handler only if the file changedhandlers:- name: restart appansible.builtin.service: { name: app, state: restarted }
Loops and conditionals
Two more everyday constructs. loop repeats a task over a list — install ten packages, create five users — without copy-pasting the task. when gates a task on a condition, most often a fact, so the same play does the right thing on different OSes or only acts when needed. Together with handlers, these cover the bulk of real playbook logic.
- name: Install base packagesansible.builtin.apt: { name: "{{ item }}", state: present }loop: [git, curl, ufw]when: ansible_facts['os_family'] == "Debian"