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 Check if File Exists: stat Module with when Conditional (Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

How to check if a file exists in Ansible with the stat module and when conditional. Verify file existence, check directories, test before actions.

Ansible Check if File Exists: stat Module with when Conditional (Guide)

How to check if a file exists in Ansible?

See also: Ansible Check If Directory Exists: stat Module Guide

Ansible check file exists

Today we're talking about the Ansible module stat. The full name is ansible.builtin.stat, which means that is part of the collection of modules "builtin" with ansible and shipped with it. It's a module pretty stable and out for years. It works in a different variety of operating systems. It retrieves a file entry or a file system status. For Windows target use the ansible.windows.win_stat module instead.

Mandatory Parameters

  • path string

Main Return Values

  • stat complex - exists
The only mandatory parameter is "path" which is the filesystem full path of the object to check. The module returns a complex object, the property that is interesting for us is "exists". This attribute is "true" if the object exists.

## Playbook Let's jump in a real-life playbook to check if a file exists with Ansible.

code

  • file_exist.yml
---
- name: check if a file exist
  hosts: all
  become: false
  vars:
    myfile: /home/devops/test.txt
  tasks:
    - name: check if a file exists
      ansible.builtin.stat:
        path: "{{ myfile }}"
      register: file_data
    - name: report file exists
      ansible.builtin.debug:
        msg: "The file {{ myfile }} exist"
      when: file_data.stat.exists
    - name: report file not exists
      ansible.builtin.debug:
        msg: "The file {{ myfile }} doesn't exist"
      when: not file_data.stat.exists

code with ❤️ in GitHub

See also: Ansible win_stat: Check if File or Directory Exists on Windows (Examples)

Conclusion

Now you know how to check if a file exists with Ansible.

Advanced File Checks

Check file and take action

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

- name: Copy default config if missing
  ansible.builtin.copy:
    src: files/default-config.yml
    dest: /etc/myapp/config.yml
    mode: '0644'
  when: not config_file.stat.exists

- name: Read existing config
  ansible.builtin.slurp:
    src: /etc/myapp/config.yml
  register: config_content
  when: config_file.stat.exists

Verify file checksum (integrity check)

- name: Get file checksum
  ansible.builtin.stat:
    path: /opt/myapp/binary
    checksum_algorithm: sha256
  register: binary_info

- name: Fail if binary is corrupted
  ansible.builtin.fail:
    msg: "Binary checksum mismatch! Expected {{ expected_checksum }}"
  when:
    - binary_info.stat.exists
    - binary_info.stat.checksum != expected_checksum

Check file age

- name: Get file info
  ansible.builtin.stat:
    path: /var/log/myapp/app.log
  register: log_file

- name: Rotate if file is larger than 100MB
  ansible.builtin.command: logrotate -f /etc/logrotate.d/myapp
  when:
    - log_file.stat.exists
    - log_file.stat.size > 104857600
  become: true

Check multiple files exist

- name: Check required files
  ansible.builtin.stat:
    path: "{{ item }}"
  register: required_files
  loop:
    - /etc/ssl/certs/myapp.crt
    - /etc/ssl/private/myapp.key
    - /etc/myapp/config.yml

- name: Fail if any required file is missing
  ansible.builtin.fail:
    msg: "Missing required file: {{ item.item }}"
  loop: "{{ required_files.results }}"
  when: not item.stat.exists
- name: Check path type
  ansible.builtin.stat:
    path: /usr/bin/python
  register: python_path

- name: Show Python path details
  ansible.builtin.debug:
    msg: >
      Path: /usr/bin/python
      Exists: {{ python_path.stat.exists }}
      Is symlink: {{ python_path.stat.islnk | default(false) }}
      Links to: {{ python_path.stat.lnk_source | default('N/A') }}

See also: Ansible Set File Permissions 755: chmod with file Module Guide

stat Module vs Other Approaches

ApproachUse Case
stat + whenCheck before acting (most flexible)
copy with force: falseCopy file only if dest doesn't exist
file with state: fileFails if file doesn't exist
lineinfile with create: trueCreate file if missing, add line
templateAlways overwrites with template output

FAQ

How do I check if a file exists on Windows?

- name: Check file on Windows
  ansible.windows.win_stat:
    path: C:\Program Files\MyApp\config.ini
  register: win_file
  
- name: File status
  ansible.builtin.debug:
    msg: "File exists: {{ win_file.stat.exists }}"

Why does stat fail with "Permission denied"?

The Ansible connection user needs read access to the parent directory. Use become: true to check files in restricted directories.

How do I get the file's content along with stat?

stat doesn't read content. Use slurp (for small files) or fetch (to download):

- name: Read file content
  ansible.builtin.slurp:
    src: /etc/myapp/config.yml
  register: file_content
  when: config_file.stat.exists

- name: Decode content
  ansible.builtin.debug:
    msg: "{{ file_content.content | b64decode }}"

Check File Exists

- ansible.builtin.stat:
    path: /etc/myapp/config.yml
  register: config_file

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

Check Multiple Files

- stat: { path: "{{ item }}" }
  loop:
    - /etc/nginx/nginx.conf
    - /etc/myapp/config.yml
    - /opt/myapp/app.jar
  register: file_checks

- debug:
    msg: "{{ item.item }} exists: {{ item.stat.exists }}"
  loop: "{{ file_checks.results }}"

File Type Checks

- stat: { path: /opt/myapp }
  register: path

- debug:
    msg:
      - "Is file: {{ path.stat.isreg | default(false) }}"
      - "Is directory: {{ path.stat.isdir | default(false) }}"
      - "Is symlink: {{ path.stat.islnk | default(false) }}"
      - "Is socket: {{ path.stat.issock | default(false) }}"

File Properties

- stat: { path: /opt/myapp/deploy.sh }
  register: script

- debug:
    msg:
      - "Size: {{ script.stat.size }} bytes"
      - "Mode: {{ script.stat.mode }}"
      - "Owner: {{ script.stat.pw_name }}"
      - "Group: {{ script.stat.gr_name }}"
      - "Modified: {{ script.stat.mtime }}"
  when: script.stat.exists

Checksum Verification

- stat:
    path: /opt/myapp/app.jar
    checksum_algorithm: sha256
  register: app_file

- debug:
    msg: "SHA256: {{ app_file.stat.checksum }}"
  when: app_file.stat.exists

# Compare checksums
- fail:
    msg: "File integrity check failed!"
  when:
    - app_file.stat.exists
    - app_file.stat.checksum != expected_checksum

Deployment Patterns

Skip if already deployed

- stat: { path: /opt/myapp-{{ version }}/app.jar }
  register: deployed

- block:
    - get_url:
        url: "https://releases.example.com/app-{{ version }}.jar"
        dest: /opt/myapp-{{ version }}/app.jar
    - service: name=myapp state=restarted
  when: not deployed.stat.exists
  become: true

Backup before overwrite

- stat: { path: /etc/nginx/nginx.conf }
  register: nginx_conf

- copy:
    src: /etc/nginx/nginx.conf
    dest: "/etc/nginx/nginx.conf.bak.{{ ansible_date_time.epoch }}"
    remote_src: true
  when: nginx_conf.stat.exists
  become: true

File age check

- stat: { path: /tmp/cache.json }
  register: cache

- set_fact:
    cache_expired: "{{ (ansible_date_time.epoch | int) - (cache.stat.mtime | int) > 3600 }}"
  when: cache.stat.exists

- command: /opt/refresh-cache.sh
  when: not cache.stat.exists or cache_expired | default(true)

Windows Equivalent

- ansible.windows.win_stat:
    path: C:\Program Files\MyApp\config.xml
  register: win_file

- debug: msg="Config exists"
  when: win_file.stat.exists

FAQ

Does stat fail if file doesn't exist?

No — stat always succeeds. Check result.stat.exists for existence.

stat vs find?

stat checks a single known path. find searches for files matching patterns, size, or age criteria.

How do I check a remote file from the controller?

stat runs on the remote host. For controller files, use delegate_to: localhost or lookup('file').

Check File Exists

- ansible.builtin.stat:
    path: /etc/myapp/config.yml
  register: config_file

- debug:
    msg: "Config {{ 'exists' if config_file.stat.exists else 'missing' }}"

Conditional Task

- stat:
    path: /opt/myapp/.installed
  register: installed

- name: Run installer only if not already installed
  command: /opt/myapp/install.sh
  when: not installed.stat.exists
  become: true

Check Multiple Files

- stat:
    path: "{{ item }}"
  loop:
    - /etc/myapp/config.yml
    - /opt/myapp/app.jar
    - /var/log/myapp
  register: file_checks

- debug:
    msg: "MISSING: {{ item.item }}"
  loop: "{{ file_checks.results }}"
  when: not item.stat.exists

Check File Properties

- stat:
    path: /opt/scripts/deploy.sh
  register: script

- debug:
    msg: |
      Size: {{ script.stat.size }} bytes
      Mode: {{ script.stat.mode }}
      Owner: {{ script.stat.pw_name }}
      Modified: {{ script.stat.mtime }}
      Is executable: {{ script.stat.executable }}
  when: script.stat.exists

Create If Missing

- stat:
    path: /etc/myapp/config.yml
  register: config

- template:
    src: default-config.yml.j2
    dest: /etc/myapp/config.yml
  when: not config.stat.exists
  become: true

Check If File Is Empty

- stat:
    path: /var/log/myapp/error.log
  register: error_log

- debug:
    msg: "Error log has content!"
  when: error_log.stat.exists and error_log.stat.size > 0
- stat:
    path: /opt/myapp/current
  register: current_link

- debug:
    msg: "Points to: {{ current_link.stat.lnk_source }}"
  when: current_link.stat.exists and current_link.stat.islnk

Verify Checksum

- stat:
    path: /opt/myapp/app.jar
    checksum_algorithm: sha256
  register: current_file

- debug:
    msg: "File needs updating"
  when: not current_file.stat.exists or current_file.stat.checksum != expected_checksum

FAQ

stat vs creates/removes?

creates/removes only work with command/shell modules. stat works everywhere and returns full metadata.

Why check before creating?

For idempotency when using command/shell. Modules like file, copy, and template are already idempotent — they check internally.

How to check on the controller (local)?

- stat: { path: /local/file }
  delegate_to: localhost
  register: local_file

Category: installation

Watch the video: Ansible Check if File Exists: stat Module with when Conditional (Guide) — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home