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 Directory Exists: stat Module Guide

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

How to check if files and directories exist with Ansible stat module. Use stat results in conditionals, check permissions, size, and timestamps.

Ansible Check If Directory Exists: stat Module Guide

How to check if a directory exists in Ansible?

I’m going to show you a live Playbook and some simple Ansible code. I’m Luca Berton and welcome to today’s episode of Ansible Pilot.

See also: Ansible Create Directory: file Module with state=directory (Guide)

Ansible check directory 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.

Main parameters and return values

path _string_

The only mandatory parameter is “path” which is the filesystem full path of the object to check. • stat _complex_

The module returns a complex object, the property that is interesting for us is “isdir”. This attribute is “true” if the object is a directory.

See also: Ansible Create Symlink: file Module with state=link (Guide)

Demo

Let’s jump in a real-life playbook to check if a directory exists with Ansible.

code

• directory_check_exists.yml
---
- name: check if the directory exists
  hosts: all
  become: false
  vars:
    directory: "/tmp"
  tasks:
    - name: Check if the directory exists
      ansible.builtin.stat:
        path: "{{ directory }}"
      register: dir_to_check

- name: Directory found ansible.builtin.debug: msg: "Directory {{ directory }} present" when: dir_to_check.stat.isdir is defined and dir_to_check.stat.isdir

code with ❤️ in GitHub

Conclusion

Now you know better the Ansible module stat and you could use it successfully in your playbook.

See also: Ansible Create File with Content: copy Module content Parameter

How It Works

The ansible.builtin.stat module retrieves file or directory metadata without modifying anything. Combined with register and when, you can create conditional logic based on filesystem state.

Complete Examples

Check directory and create if missing

---
- name: Ensure directory exists
  hosts: all
  tasks:
    - name: Check if /opt/myapp exists
      ansible.builtin.stat:
        path: /opt/myapp
      register: myapp_dir

- name: Create directory if not present ansible.builtin.file: path: /opt/myapp state: directory owner: appuser group: appuser mode: '0755' become: true when: not myapp_dir.stat.exists

- name: Show directory info ansible.builtin.debug: msg: "Directory exists: {{ myapp_dir.stat.exists }}, isdir: {{ myapp_dir.stat.isdir | default(false) }}"

Check multiple directories

- name: Verify required directories exist
  ansible.builtin.stat:
    path: "{{ item }}"
  register: dir_checks
  loop:
    - /opt/myapp
    - /var/log/myapp
    - /etc/myapp

- name: Report missing directories ansible.builtin.debug: msg: "MISSING: {{ item.item }}" loop: "{{ dir_checks.results }}" when: not item.stat.exists

Check if path is a directory (not a file)

- name: Check path type
  ansible.builtin.stat:
    path: /opt/myapp
  register: path_info

- name: Fail if path exists but is not a directory ansible.builtin.fail: msg: "/opt/myapp exists but is not a directory!" when: path_info.stat.exists and not path_info.stat.isdir

Useful stat Properties

| Property | Type | Description | |----------|------|-------------| | stat.exists | bool | Path exists | | stat.isdir | bool | Is a directory | | stat.isreg | bool | Is a regular file | | stat.islnk | bool | Is a symlink | | stat.size | int | Size in bytes | | stat.uid | int | Owner user ID | | stat.gid | int | Owner group ID | | stat.mode | string | Permissions (e.g., "0755") | | stat.pw_name | string | Owner username | | stat.gr_name | string | Owner group name | | stat.mtime | float | Last modified timestamp |

FAQ

Why not just use file with state: directory?

file state=directory is idempotent — it creates the directory if missing. Use stat when you need to make decisions based on whether the directory exists (e.g., skip deployment, trigger different logic).

How do I check directory permissions?

- name: Check permissions
  ansible.builtin.stat:
    path: /opt/myapp
  register: dir_info

- name: Fix permissions if wrong ansible.builtin.file: path: /opt/myapp mode: '0755' when: dir_info.stat.exists and dir_info.stat.mode != '0755' become: true

Check Directory Exists

- name: Check if directory exists
  ansible.builtin.stat:
    path: /opt/myapp
  register: dir_check

- name: Create only if missing ansible.builtin.file: path: /opt/myapp state: directory when: not dir_check.stat.exists become: true

- name: Skip if already deployed ansible.builtin.unarchive: src: myapp.tar.gz dest: /opt/myapp when: not dir_check.stat.exists

Check File Exists

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

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

Check File Type

- stat:
    path: /opt/myapp
  register: path_info

- debug: msg: - "Exists: {{ path_info.stat.exists }}" - "Is directory: {{ path_info.stat.isdir | default(false) }}" - "Is file: {{ path_info.stat.isreg | default(false) }}" - "Is symlink: {{ path_info.stat.islnk | default(false) }}" - "Size: {{ path_info.stat.size | default(0) }} bytes" - "Owner: {{ path_info.stat.pw_name | default('N/A') }}" - "Mode: {{ path_info.stat.mode | default('N/A') }}" when: path_info.stat.exists

Common Patterns

Deploy if not already present

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

- get_url: url: "https://releases.example.com/app-{{ version }}.jar" dest: /opt/myapp/app.jar when: not app.stat.exists

Backup before overwriting

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

- copy: src: /etc/nginx/nginx.conf dest: /etc/nginx/nginx.conf.bak remote_src: true when: nginx_conf.stat.exists

Check file age

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

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

- debug: msg: "Cache is {{ cache_age }} seconds old" when: cache.stat.exists and (cache_age | int) > 3600

Check file size

- stat: { path: /var/log/myapp.log }
  register: log_file

- name: Rotate if > 100MB command: logrotate -f /etc/logrotate.d/myapp when: log_file.stat.exists and log_file.stat.size > 104857600

Stat Properties

| Property | Description | |----------|-------------| | exists | Path exists | | isdir | Is directory | | isreg | Is regular file | | islnk | Is symlink | | size | File size (bytes) | | mode | Permission mode | | pw_name | Owner username | | gr_name | Group name | | mtime | Modification time (epoch) | | checksum | SHA1 hash | | md5 | MD5 hash (if get_md5: true) |

FAQ

Why does stat not fail when file doesn't exist?

By design — stat always succeeds. Check result.stat.exists to determine if the path exists.

How do I check on Windows?

- ansible.windows.win_stat:
    path: C:\Program Files\MyApp
  register: win_dir

stat vs find module?

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

Check Directory Exists

- ansible.builtin.stat:
    path: /opt/myapp
  register: app_dir

- debug: msg: "/opt/myapp exists: {{ app_dir.stat.exists }}"

- file: path: /opt/myapp state: directory when: not app_dir.stat.exists become: true

Check File Exists

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

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

Check File Type

- stat:
    path: /opt/myapp
  register: result

- debug: msg: | Exists: {{ result.stat.exists }} Is directory: {{ result.stat.isdir | default(false) }} Is file: {{ result.stat.isreg | default(false) }} Is link: {{ result.stat.islnk | default(false) }}

Check Permissions

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

- file: path: /opt/scripts/deploy.sh mode: '0755' when: script.stat.exists and script.stat.mode != '0755' become: true

Check File Size

- stat:
    path: /var/log/myapp/app.log
  register: logfile

- name: Rotate large log command: logrotate -f /etc/logrotate.d/myapp when: logfile.stat.exists and logfile.stat.size > 104857600 # 100MB become: true

Check Checksum

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

- get_url: url: "{{ download_url }}" dest: /opt/myapp/app.jar checksum: "sha256:{{ expected_checksum }}" when: not current.stat.exists or current.stat.checksum != expected_checksum

Check Multiple Paths

- stat:
    path: "{{ item }}"
  loop:
    - /opt/myapp/config.yml
    - /opt/myapp/data
    - /opt/myapp/logs
  register: paths

- debug: msg: "{{ item.item }}: {{ 'exists' if item.stat.exists else 'MISSING' }}" loop: "{{ paths.results }}"

stat Attributes

| Attribute | Description | |-----------|-------------| | .exists | Path exists | | .isdir | Is directory | | .isreg | Is regular file | | .islnk | Is symlink | | .mode | Permissions (e.g., '0755') | | .size | Size in bytes | | .uid / .gid | Owner/group IDs | | .pw_name / .gr_name | Owner/group names | | .mtime | Modification time (epoch) | | .checksum | File checksum | | .lnk_source | Symlink target |

FAQ

Why use stat instead of just using creates?

creates only works with command/shell. stat works everywhere and gives you full file metadata for complex conditions.

How to handle "attribute not found" errors?

Use default() filter: result.stat.isdir | default(false). Attributes like isdir only exist when exists is true.

stat on remote vs local?

stat runs on the managed node. For local files, use delegate_to: localhost or lookup('file').

Related Articles

conditional execution with Ansible whenhow Ansible become works under the hoodWindows management with Ansible

Category: troubleshooting

Watch the video: Ansible Check If Directory Exists: stat Module Guide — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home