Ansible file Module: 20 Practical Examples Cookbook (Create, Delete, Permissions)
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
20 practical Ansible file module examples. Create directories, delete files, set permissions, create symlinks, manage ownership.
The file module manages files, directories, and symlinks on remote hosts — permissions, ownership, creation, and deletion. Here are 20 production-ready examples.
1. Create a Directory
- name: Create application directory
ansible.builtin.file:
path: /opt/myapp
state: directory
mode: '0755'
owner: deploy
group: deploy
See also: ansible.builtin.file Module: Manage Files, Directories & Symlinks (Complete Guide)
2. Create Nested Directories
- name: Create full directory tree
ansible.builtin.file:
path: /opt/myapp/releases/current/logs
state: directory
mode: '0755'
owner: deploy
group: deploy
# Creates ALL parent directories automatically
3. Create Multiple Directories
- name: Create application directory structure
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: '0755'
owner: deploy
group: deploy
loop:
- /opt/myapp/config
- /opt/myapp/logs
- /opt/myapp/data
- /opt/myapp/backups
- /opt/myapp/tmp
See also: Ansible Development: Write Custom Modules, Plugins & Collections
4. Create a Symlink
- name: Link current release
ansible.builtin.file:
src: /opt/myapp/releases/v2.5.0
dest: /opt/myapp/current
state: link
owner: deploy
group: deploy
5. Create a Relative Symlink
- name: Relative symlink for log rotation
ansible.builtin.file:
src: ../shared/logs
dest: /opt/myapp/current/logs
state: link
See also: Ansible for Windows: Complete Guide to Windows Automation (2026)
6. Set File Permissions
- name: Secure private key
ansible.builtin.file:
path: /home/deploy/.ssh/id_rsa
mode: '0600'
owner: deploy
group: deploy
- name: Make script executable
ansible.builtin.file:
path: /opt/myapp/bin/start.sh
mode: '0755'
7. Set Permissions Recursively
- name: Fix ownership on entire app directory
ansible.builtin.file:
path: /opt/myapp
state: directory
owner: deploy
group: deploy
recurse: true
8. Set Directory with Sticky Bit
- name: Create shared directory with sticky bit
ansible.builtin.file:
path: /opt/shared
state: directory
mode: '1777' # Like /tmp — everyone can write, only owner can delete
9. Set SGID on Directory
- name: Shared group directory (new files inherit group)
ansible.builtin.file:
path: /opt/teamdata
state: directory
mode: '2775'
group: developers
10. Delete a File
- name: Remove old config
ansible.builtin.file:
path: /etc/myapp/old-config.conf
state: absent
11. Delete a Directory Recursively
- name: Remove old release
ansible.builtin.file:
path: /opt/myapp/releases/v1.0.0
state: absent
# Removes directory and ALL contents
12. Touch a File (Create Empty or Update Timestamp)
- name: Create marker file
ansible.builtin.file:
path: /opt/myapp/.deployed
state: touch
mode: '0644'
owner: deploy
group: deploy
- name: Update modification time
ansible.builtin.file:
path: /opt/myapp/logs/access.log
state: touch
modification_time: preserve # Don't change mtime
access_time: "202604130000.00"
13. Create a Hard Link
- name: Create hard link for shared config
ansible.builtin.file:
src: /etc/myapp/shared.conf
dest: /etc/myapp/service-a.conf
state: hard
14. Ensure File Exists (Without Overwriting)
- name: Ensure log file exists
ansible.builtin.file:
path: /var/log/myapp/app.log
state: touch
mode: '0644'
owner: myapp
group: myapp
modification_time: preserve
access_time: preserve
15. Application Deployment Directory Structure
- name: Build full deployment tree
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
mode: "{{ item.mode | default('0755') }}"
owner: "{{ app_user }}"
group: "{{ app_group }}"
loop:
- { path: "{{ deploy_to }}/releases" }
- { path: "{{ deploy_to }}/shared/config" }
- { path: "{{ deploy_to }}/shared/logs", mode: '0775' }
- { path: "{{ deploy_to }}/shared/pids" }
- { path: "{{ deploy_to }}/shared/tmp" }
- { path: "{{ deploy_to }}/shared/sockets", mode: '0770' }
vars:
deploy_to: /opt/myapp
app_user: deploy
app_group: deploy
16. Symlink Shared Resources to Current Release
- name: Link shared resources
ansible.builtin.file:
src: "{{ deploy_to }}/shared/{{ item }}"
dest: "{{ deploy_to }}/current/{{ item }}"
state: link
force: true
loop:
- config/database.yml
- config/secrets.yml
- logs
- tmp
- pids
17. Clean Old Releases (Keep Last 5)
- name: List releases
ansible.builtin.find:
paths: /opt/myapp/releases
file_type: directory
register: releases
- name: Remove old releases (keep 5)
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ (releases.files | sort(attribute='mtime') | list)[:-5] }}"
when: releases.files | length > 5
18. Set SELinux Context
- name: Set SELinux context for web content
ansible.builtin.file:
path: /var/www/html
state: directory
setype: httpd_sys_content_t
recurse: true
when: ansible_selinux.status == "enabled"
19. Conditional Directory Creation
- name: Create environment-specific dirs
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: '0755'
loop:
- /opt/myapp/config
- "{{ '/opt/myapp/debug' if environment == 'staging' else '/opt/myapp/cache' }}"
- "{{ '/opt/myapp/ssl' if ssl_enabled else omit }}"
when: item is not none
20. Verify Permissions (Audit Mode)
- name: Check file permissions
ansible.builtin.file:
path: "{{ item.path }}"
mode: "{{ item.mode }}"
owner: "{{ item.owner }}"
check_mode: true
register: perm_check
loop:
- { path: /etc/ssh/sshd_config, mode: '0644', owner: root }
- { path: /etc/shadow, mode: '0640', owner: root }
- { path: /etc/crontab, mode: '0644', owner: root }
- name: Report permission drift
ansible.builtin.debug:
msg: "⚠️ {{ item.item.path }} permissions have drifted"
loop: "{{ perm_check.results }}"
when: item.changed
FAQ
What's the difference between file, copy, and template modules?
file manages metadata — permissions, ownership, existence, symlinks. It doesn't write content. Use copy for static files, template for Jinja2 templates, and file for everything else (directories, symlinks, permissions).
Does recurse: true work with mode?
recurse: true applies owner and group recursively but does NOT apply mode recursively (by design — you usually want different modes for files vs directories). Use find + file for recursive permission changes with different file/directory modes.
How do I create a directory only if it doesn't exist?
state: directory is already idempotent — it creates the directory if missing and does nothing if it exists. You don't need a separate check.
Can I manage Windows files with the file module?
Use ansible.windows.win_file for Windows targets. The ansible.builtin.file module is for Unix/Linux only.
Conclusion
The file module handles everything about files except their content — directories, symlinks, permissions, ownership, SELinux contexts, and cleanup. Combine it with copy, template, and find for complete file management. Every example above is idempotent and production-ready.
Related Articles
• Ansible copy vs template vs lineinfile • Ansible Create Directory Guide • Ansible Delete File Guide • How to Make Playbooks IdempotentCategory: troubleshooting