Introduction
The ansible.builtin.file module is one of the most versatile modules in Ansible. While it handles everything from creating directories to managing symlinks, one of its most common uses is creating empty files with state: touch — equivalent to the Linux touch command but with Ansible's idempotency and remote execution capabilities.
This guide covers all the ways to use the file module for file creation and management.
Module Reference
Full name: ansible.builtin.file
Collection: ansible.builtin (included with Ansible)
Key Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string | Yes | File or directory path (aliases: dest, name) |
state | string | No | file, directory, touch, link, hard, absent |
mode | string | No | File permissions (e.g., '0644', 'u+rw,g-wx') |
owner | string | No | File owner |
group | string | No | File group |
recurse | bool | No | Recursively set attributes (directories only) |
modification_time | string | No | Set modification time (preserve or timestamp) |
access_time | string | No | Set access time (preserve or timestamp) |
State Values
| State | Behavior |
|---|---|
touch | Create file if missing; update timestamps if exists |
file | Verify file exists and set attributes (fail if missing) |
directory | Create directory (and parents) if missing |
absent | Delete file or directory |
link | Create symbolic link |
hard | Create hard link |
Create an Empty File
The simplest use case — create a file if it doesn't exist:
---
- name: Create an empty file
hosts: all
tasks:
- name: Create example.txt
ansible.builtin.file:
path: ~/example.txt
state: touch
With Permissions and Ownership
- name: Create file with specific permissions
ansible.builtin.file:
path: /var/log/myapp/app.log
state: touch
mode: '0644'
owner: appuser
group: appgroup
Create Only If Not Exists (Preserve Timestamps)
By default, state: touch updates the file's timestamps every time. To create the file but not modify it if it already exists:
- name: Create file only if missing (don't update timestamps)
ansible.builtin.file:
path: /opt/app/.initialized
state: touch
modification_time: preserve
access_time: preserve
Create a Directory
- name: Create directory with parents
ansible.builtin.file:
path: /opt/myapp/logs/archive
state: directory
mode: '0755'
owner: appuser
group: appgroup
This creates all parent directories if they don't exist — like mkdir -p.
Recursive Permission Setting
- name: Set permissions recursively
ansible.builtin.file:
path: /opt/myapp
state: directory
mode: '0755'
owner: appuser
group: appgroup
recurse: true
Delete Files and Directories
- name: Remove a file
ansible.builtin.file:
path: /tmp/old-config.yml
state: absent
- name: Remove a directory and all contents
ansible.builtin.file:
path: /tmp/build-artifacts
state: absent
Create Symbolic Links
- name: Create symlink
ansible.builtin.file:
src: /opt/myapp/releases/v2.1.0
dest: /opt/myapp/current
state: link
- name: Create symlink for configuration
ansible.builtin.file:
src: /etc/nginx/sites-available/myapp.conf
dest: /etc/nginx/sites-enabled/myapp.conf
state: link
Practical Use Cases
Application Deployment Flag Files
- name: Deploy application
hosts: web_servers
tasks:
- name: Download release
ansible.builtin.get_url:
url: "https://releases.example.com/app-{{ version }}.tar.gz"
dest: "/opt/app/releases/app-{{ version }}.tar.gz"
- name: Extract release
ansible.builtin.unarchive:
src: "/opt/app/releases/app-{{ version }}.tar.gz"
dest: "/opt/app/releases/"
remote_src: true
- name: Create deployment marker
ansible.builtin.file:
path: "/opt/app/releases/{{ version }}/.deployed"
state: touch
mode: '0444'
Log Rotation Preparation
- name: Prepare log directories for new month
ansible.builtin.file:
path: "/var/log/myapp/{{ item }}"
state: directory
mode: '0755'
owner: syslog
group: adm
loop:
- "{{ lookup('pipe', 'date +%Y-%m') }}"
- archive
- errors
Ensure Configuration Directory Structure
- name: Create application directory structure
ansible.builtin.file:
path: "{{ item.path }}"
state: "{{ item.state | default('directory') }}"
mode: "{{ item.mode | default('0755') }}"
owner: appuser
group: appgroup
loop:
- { path: '/opt/myapp' }
- { path: '/opt/myapp/config' }
- { path: '/opt/myapp/data', mode: '0700' }
- { path: '/opt/myapp/logs' }
- { path: '/opt/myapp/tmp', mode: '0777' }
- { path: '/opt/myapp/config/app.conf', state: 'touch', mode: '0644' }
Lock Files for Idempotent Tasks
- name: Run migration only once
block:
- name: Check for migration lock
ansible.builtin.stat:
path: /opt/app/.migration-v2-complete
register: migration_lock
- name: Run database migration
ansible.builtin.command: /opt/app/migrate.sh
when: not migration_lock.stat.exists
- name: Create migration lock file
ansible.builtin.file:
path: /opt/app/.migration-v2-complete
state: touch
mode: '0444'
when: not migration_lock.stat.exists
Common Mistakes
Forgetting Quotes on Mode
# WRONG — 0644 is interpreted as octal integer (420 decimal)
mode: 0644
# CORRECT — quoted string preserves the octal notation
mode: '0644'
Using touch When file Is Needed
# This creates the file if missing (may not be desired)
state: touch
# This fails if the file doesn't exist (assertion check)
state: file
Path Expansion
# ~ expands on the remote host, not the control node
path: ~/config.yml # Creates in remote user's home
# Use absolute paths for predictability
path: /home/appuser/config.yml
file Module vs Other Modules
| Task | Best Module |
|---|---|
| Create empty file | file (state: touch) |
| Create file with content | copy (with content:) |
| Create file from template | template |
| Set permissions only | file (state: file) |
| Create directories | file (state: directory) |
| Copy existing file | copy (with src:) |
Related Articles
- Ansible File Module: Manage File Properties
- How to Check If a Directory Exists
- Copy Files to Remote Hosts: Ansible copy Module
- Ansible template Module Guide
- Ansible lineinfile Module
- Remove a File: Ansible file Module
- Ansible Best Practices Guide
Conclusion
The ansible.builtin.file module with state: touch is the standard way to create empty files in Ansible. Combined with mode, owner, and group parameters, it handles everything from simple file creation to complex directory structures. Use modification_time: preserve when you need to create files without updating timestamps on subsequent runs, and use state: absent for clean removal of files and directories.