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.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home