AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible when Conditional: Complete Guide with Examples

By Luca Berton · Published 2026-04-03 · Category: installation

Complete guide to Ansible when conditionals. Use when statements with facts, variables, registered results, and complex boolean logic in playbooks.

The when statement is Ansible's conditional — it controls whether a task runs based on variables, facts, registered results, or any Jinja2 expression.

Basic when Syntax

- name: Install nginx on Debian
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian"

Important: when uses raw Jinja2 expressions — do NOT wrap in {{ }}.

See also: Ansible Loops: Complete Guide with loop, with_items & Examples

Boolean Conditions

# Variable is true
- debug: msg="Debug mode"
  when: debug_mode

# Variable is false - debug: msg="Production mode" when: not debug_mode

# Variable equals value - debug: msg="Version 2" when: app_version == "2.0"

# Numeric comparison - debug: msg="Low disk" when: disk_free_gb < 10

OS and Distribution Conditions

# By OS family
- name: Install on RedHat family
  ansible.builtin.dnf:
    name: httpd
    state: present
  when: ansible_os_family == "RedHat"

# By distribution - name: Install on Ubuntu only ansible.builtin.apt: name: nginx state: present when: ansible_distribution == "Ubuntu"

# By version - name: Only on Ubuntu 24.04+ ansible.builtin.apt: name: nginx state: present when: - ansible_distribution == "Ubuntu" - ansible_distribution_major_version | int >= 24

See also: Ansible ternary Filter: Inline If-Else Conditional in Jinja2 (Guide)

AND / OR Logic

AND (all conditions must be true)

# Method 1: List (implicit AND)
- name: Install on Ubuntu production servers
  ansible.builtin.apt:
    name: nginx
  when:
    - ansible_distribution == "Ubuntu"
    - env == "production"
    - ansible_memtotal_mb >= 2048

# Method 2: Explicit AND - name: Same thing with 'and' ansible.builtin.apt: name: nginx when: ansible_distribution == "Ubuntu" and env == "production"

OR (any condition)

- name: Install on Debian or Ubuntu
  ansible.builtin.apt:
    name: nginx
  when: ansible_distribution == "Debian" or ansible_distribution == "Ubuntu"

Complex combinations

- name: Complex condition
  ansible.builtin.debug:
    msg: "Condition met"
  when: >-
    (ansible_distribution == "Ubuntu" and ansible_distribution_major_version | int >= 22) or
    (ansible_distribution == "Debian" and ansible_distribution_major_version | int >= 12)

Variable Testing

# Variable is defined
- debug: msg="{{ my_var }}"
  when: my_var is defined

# Variable is not defined - debug: msg="Using default" when: custom_port is not defined

# Variable is not empty - debug: msg="{{ my_var }}" when: my_var | length > 0

# Variable is in a list - debug: msg="Valid environment" when: env in ['production', 'staging', 'development']

# Variable contains string - debug: msg="Found keyword" when: "'error' in log_output"

See also: Ansible check_mode: Dry Run & Test Playbooks Without Making Changes

Registered Variables

- name: Check if file exists
  ansible.builtin.stat:
    path: /etc/myapp/config.yml
  register: config_file

- name: Create config if missing ansible.builtin.template: src: config.yml.j2 dest: /etc/myapp/config.yml when: not config_file.stat.exists

- name: Check service status ansible.builtin.command: systemctl is-active myapp register: service_status ignore_errors: true

- name: Start service if not running ansible.builtin.service: name: myapp state: started when: service_status.rc != 0

when with Loops

- name: Install only packages that aren't installed
  ansible.builtin.apt:
    name: "{{ item.name }}"
    state: present
  loop:
    - { name: nginx, install: true }
    - { name: apache2, install: false }
    - { name: postgresql, install: true }
  when: item.install

when with Blocks

- name: RedHat-specific tasks
  when: ansible_os_family == "RedHat"
  block:
    - name: Install EPEL
      ansible.builtin.dnf:
        name: epel-release
        state: present

- name: Install packages ansible.builtin.dnf: name: "{{ item }}" state: present loop: - nginx - postgresql-server

Test Filters

# String tests
when: my_var is match("^web\d+")
when: my_var is search("error")
when: my_var is regex("^[a-z]+$")

# Type tests when: my_var is string when: my_var is number when: my_var is mapping # dict when: my_var is iterable

# Comparison tests when: my_version is version('2.0', '>=') when: path is file when: path is directory when: path is link

Common Patterns

Skip task in check mode

- name: Run only in real mode
  ansible.builtin.command: /opt/deploy.sh
  when: not ansible_check_mode

First run detection

- name: Check if already configured
  ansible.builtin.stat:
    path: /opt/app/.configured
  register: configured

- name: Run initial setup ansible.builtin.command: /opt/app/setup.sh when: not configured.stat.exists

- name: Mark as configured ansible.builtin.file: path: /opt/app/.configured state: touch when: not configured.stat.exists

FAQ

Why can't I use {{ }} in when statements?

when already evaluates as a Jinja2 expression. Adding {{ }} would double-evaluate and cause errors. Just use variable names directly.

How do I check if a variable is true/false?

when: my_var checks truthiness (non-empty, non-zero, not None). when: my_var == true checks for boolean True specifically.

Can I use when with include_tasks?

Yes. The condition applies to the include itself — all tasks in the included file will be skipped if the condition is false.

Basic when

- name: Install on Debian only
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian"
  become: true

Common Conditions

# OS family
when: ansible_os_family == "RedHat"
when: ansible_distribution == "Ubuntu"
when: ansible_distribution_version == "24.04"

# Architecture when: ansible_architecture == "x86_64"

# Variable defined/undefined when: my_var is defined when: my_var is not defined

# Boolean when: enable_feature when: not disable_logging when: enable_ssl | bool

# String checks when: env == "production" when: "'error' in command_output.stdout" when: app_version is version('2.0', '>=')

Multiple Conditions (AND)

# All must be true (implicit AND)
- apt: name=nginx
  when:
    - ansible_os_family == "Debian"
    - ansible_distribution_version is version('20.04', '>=')
    - env == "production"

OR Conditions

- yum: name=httpd
  when: ansible_distribution == "CentOS" or ansible_distribution == "Rocky"

# Complex - debug: msg="Install web server" when: > (ansible_distribution == "Ubuntu" and ansible_distribution_version == "24.04") or (ansible_distribution == "Rocky" and ansible_distribution_major_version == "9")

Based on Registered Results

- command: systemctl is-active nginx
  register: nginx_status
  ignore_errors: true
  changed_when: false

- debug: msg="Nginx is running" when: nginx_status.rc == 0

- debug: msg="Nginx is stopped" when: nginx_status.rc != 0

# Check stdout - command: cat /etc/os-release register: os_info changed_when: false

- debug: msg="Running Debian" when: "'Debian' in os_info.stdout"

Check Variable Content

# Empty check
when: my_list | length > 0
when: my_string | length > 0
when: my_var != ""
when: my_var is not none

# In list when: inventory_hostname in groups['webservers'] when: "'admin' in user_roles"

# Numeric comparison when: disk_usage | int > 80 when: ansible_memfree_mb > 1024

Conditionals with Loops

- name: Install only needed packages
  apt:
    name: "{{ item.name }}"
  loop:
    - { name: nginx, install: true }
    - { name: apache2, install: false }
    - { name: curl, install: true }
  when: item.install
  become: true

Block-Level Conditionals

- block:
    - apt: name=nginx state=present
    - template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    - service: name=nginx state=started enabled=true
  when: ansible_os_family == "Debian"
  become: true

Version Comparison

when: ansible_distribution_version is version('22.04', '>=')
when: app_version is version('3.0.0', '<')
when: ansible_python_version is version('3.8', '>=')

# Strict version comparison when: pkg_version is version('2.0.0', '>=', strict=true)

File/Path Tests

- stat: { path: /opt/myapp/config.yml }
  register: config

- template: src=config.yml.j2 dest=/opt/myapp/config.yml when: not config.stat.exists

Common Mistakes

# WRONG: Don't use {{ }} in when
when: "{{ my_var }} == 'value'"

# CORRECT: when already templates when: my_var == 'value'

# WRONG: Bare variable might be string "false" when: enable_feature

# CORRECT: Force boolean when: enable_feature | bool

FAQ

How do I negate a condition?

when: not (ansible_os_family == "Debian")
when: my_var is not defined
when: my_var != "value"

Can I use when with handlers?

Yes — handlers support when, but they only run if notified AND the condition is true.

How do I skip an entire role?

roles:
  - role: nginx
    when: install_nginx | default(true) | bool

Basic when

- apt: { name: nginx }
  when: ansible_os_family == "Debian"
  become: true

- yum: { name: nginx } when: ansible_os_family == "RedHat" become: true

Multiple Conditions (AND)

- debug:
    msg: "Production Ubuntu server"
  when:
    - ansible_distribution == "Ubuntu"
    - env == "production"
    - ansible_memtotal_mb >= 4096

OR Conditions

- debug:
    msg: "Debian-based"
  when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"

# With 'in' - debug: msg: "Supported distro" when: ansible_distribution in ["Ubuntu", "Debian", "CentOS", "Rocky"]

Check Variable Defined

- debug:
    msg: "Using custom port {{ custom_port }}"
  when: custom_port is defined

- debug: msg: "Using default port" when: custom_port is not defined

Registered Results

- command: which docker
  register: docker_check
  ignore_errors: true
  changed_when: false

- debug: msg: "Docker is installed" when: docker_check.rc == 0

- debug: msg: "Docker NOT found" when: docker_check.rc != 0

Boolean Variables

- service:
    name: nginx
    state: started
  when: enable_webserver  # true/false

- service: name: nginx state: stopped when: not enable_webserver

Conditional on Facts

# OS version
when: ansible_distribution_version is version('22.04', '>=')

# Architecture when: ansible_architecture == "x86_64"

# Memory when: ansible_memtotal_mb > 2048

# Disk space when: ansible_mounts | selectattr('mount', 'eq', '/') | map(attribute='size_available') | first > 5368709120

Conditional with Loops

- debug:
    msg: "Installing {{ item.name }}"
  loop:
    - { name: nginx, install: true }
    - { name: apache2, install: false }
  when: item.install

Conditional Blocks

- block:
    - apt: { name: nginx }
    - template: { src: nginx.conf.j2, dest: /etc/nginx/nginx.conf }
    - service: { name: nginx, state: started }
  when: ansible_os_family == "Debian"
  become: true

String Tests

when: my_string | length > 0          # Not empty
when: my_string is match("^web-.*")   # Regex match
when: "'error' in log_output.stdout"  # Contains
when: my_var is string                # Type check

FAQ

when vs failed_when vs changed_when?

when controls if a task runs. failed_when controls if a task is considered failed. changed_when controls if a task reports as changed.

Can I use Jinja2 in when?

when already evaluates as Jinja2 — don't wrap in {{ }}. Wrong: when: "{{ x }}". Right: when: x.

How to negate a condition?

Use not: when: not my_var or when: my_var is not defined.

Related Articles

rendering Jinja2 templates with AnsibleAnsible Ignore Errors GuideAnsible Check Mode Guidesubelements lookup with Ansible loopsreverse proxy with Ansible Nginx

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home