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.builtin.file Module: Manage Files, Directories & Symlinks (Complete Guide)

By Luca Berton · Published 2026-04-03 · Category: troubleshooting

Complete guide to ansible.builtin.file module. Create, delete, modify files and directories, set permissions, ownership, symlinks, SELinux context.

The ansible.builtin.file module is one of the most frequently used Ansible modules. It manages files, directories, and symlinks on remote hosts — creating, deleting, and setting permissions.

Basic Syntax

- name: Manage a file
  ansible.builtin.file:
    path: /path/to/file
    state: <file|directory|link|hard|touch|absent>
    owner: username
    group: groupname
    mode: '0755'

See also: Ansible Write to File: 5 Methods with Practical Examples (2026)

Create a Directory

- name: Create application directory
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: appuser
    group: appuser
    mode: '0755'

Create nested directories (like mkdir -p)

- name: Create nested directories
  ansible.builtin.file:
    path: /opt/myapp/config/ssl
    state: directory
    recurse: true

Create an Empty File (touch)

- name: Create empty log file
  ansible.builtin.file:
    path: /var/log/myapp.log
    state: touch
    owner: appuser
    group: appuser
    mode: '0644'

See also: Ansible file Module: 20 Practical Examples Cookbook (Create, Delete, Permissions)

- name: Create symlink
  ansible.builtin.file:
    src: /opt/myapp/current/config.yml
    dest: /etc/myapp/config.yml
    state: link
- name: Create hard link
  ansible.builtin.file:
    src: /opt/myapp/app.jar
    dest: /opt/myapp/app-latest.jar
    state: hard

Delete Files and Directories

- name: Remove a file
  ansible.builtin.file:
    path: /tmp/old-config.yml
    state: absent
- name: Remove a directory recursively
  ansible.builtin.file:
    path: /opt/myapp/old-release
    state: absent

See also: Ansible Delete File & Remove File: file Module absent State Guide

Set File Permissions

- name: Set permissions with numeric mode
  ansible.builtin.file:
    path: /opt/myapp/deploy.sh
    mode: '0755'

- name: Set permissions with symbolic mode
  ansible.builtin.file:
    path: /opt/myapp/deploy.sh
    mode: 'u+rwx,g+rx,o+rx'

- name: Add execute permission
  ansible.builtin.file:
    path: /opt/myapp/script.sh
    mode: 'a+x'

Set Owner and Group

- name: Change file ownership
  ansible.builtin.file:
    path: /opt/myapp
    owner: appuser
    group: appgroup
    recurse: true

Set SELinux Context

- name: Set SELinux context for web content
  ansible.builtin.file:
    path: /var/www/html
    setype: httpd_sys_content_t
    recurse: true

Common Parameters Reference

ParameterDescriptionRequired
pathPath to the file/directoryYes
statefile, directory, link, hard, touch, absentNo (default: file)
ownerOwner of the fileNo
groupGroup of the fileNo
modePermission mode (octal or symbolic)No
recurseRecursively set attributes (directories only)No
srcSource for link/hard stateFor links
forceForce creation of symlinksNo
followFollow symlinksNo
access_timeSet access timeNo
modification_timeSet modification timeNo

Practical Examples

Ensure application directory structure exists

- name: Create app directory structure
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: appuser
    group: appuser
    mode: '0755'
  loop:
    - /opt/myapp
    - /opt/myapp/config
    - /opt/myapp/logs
    - /opt/myapp/data

Conditional file management

- name: Create debug log only in development
  ansible.builtin.file:
    path: /var/log/myapp-debug.log
    state: touch
    mode: '0666'
  when: environment == 'development'

FAQ

What's the difference between state: file and state: touch?

state: file verifies a file exists and sets attributes but does NOT create it. state: touch creates the file if it doesn't exist (like the touch command).

How do I create a file with content?

Use ansible.builtin.copy with content parameter instead. The file module only manages file attributes, not content.

Can I use ansible.builtin.file on Windows?

No, use ansible.windows.win_file for Windows hosts.

Create Directory

- name: Create application directory
  ansible.builtin.file:
    path: /opt/myapp
    state: directory
    owner: appuser
    group: appgroup
    mode: '0755'
  become: true

Create Empty File

- name: Create log file
  ansible.builtin.file:
    path: /var/log/myapp/app.log
    state: touch
    owner: appuser
    mode: '0644'
  become: true
- name: Link current version
  ansible.builtin.file:
    src: /opt/myapp-2.5.0
    dest: /opt/myapp
    state: link
  become: true

Set Permissions Recursively

- name: Fix permissions
  ansible.builtin.file:
    path: /opt/myapp
    owner: appuser
    group: appgroup
    mode: '0755'
    recurse: true
  become: true

Delete File or Directory

- ansible.builtin.file:
    path: /opt/myapp-old
    state: absent
  become: true

Multiple Directories

- name: Create project structure
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: deploy
    mode: '0755'
  loop:
    - /opt/myapp/config
    - /opt/myapp/logs
    - /opt/myapp/data
    - /opt/myapp/tmp
  become: true
- file:
    path: "/opt/myapp-{{ version }}"
    state: directory

- unarchive:
    src: "myapp-{{ version }}.tar.gz"
    dest: "/opt/myapp-{{ version }}"

- file:
    src: "/opt/myapp-{{ version }}"
    dest: /opt/myapp-current
    state: link
  notify: restart myapp

State Reference

StateDescription
fileSet attributes (must exist)
directoryCreate directory (mkdir -p)
linkCreate symbolic link
hardCreate hard link
touchCreate empty / update timestamp
absentDelete

FAQ

Why quote mode as '0755'?

YAML interprets unquoted 0755 as decimal 493. Always quote octal permissions.

file vs copy vs template?

  • file: Create empty files, directories, links, set permissions
  • copy: Transfer files with content
  • template: Render Jinja2 templates

Does directory create parents?

Yes — like mkdir -p.

Create Directory

- ansible.builtin.file:
    path: /opt/myapp/logs
    state: directory
    owner: deploy
    group: deploy
    mode: '0755'
  become: true

Create File

- file:
    path: /opt/myapp/.env
    state: touch
    owner: deploy
    mode: '0600'
  become: true
- file:
    src: /opt/myapp/current/config.yml
    dest: /etc/myapp/config.yml
    state: link
  become: true

Set Permissions

- file:
    path: /opt/myapp/deploy.sh
    mode: '0755'
    owner: deploy
    group: deploy
  become: true

# Recursive permissions
- file:
    path: /opt/myapp
    state: directory
    owner: deploy
    group: deploy
    recurse: true
  become: true

Delete File or Directory

- file:
    path: /tmp/old-cache
    state: absent
  become: true

Create Multiple Directories

- file:
    path: "{{ item }}"
    state: directory
    owner: deploy
    mode: '0755'
  loop:
    - /opt/myapp
    - /opt/myapp/logs
    - /opt/myapp/config
    - /opt/myapp/data
    - /opt/myapp/tmp
  become: true

Deployment Directory Structure

- name: Create release directory
  file:
    path: "/opt/releases/{{ release_version }}"
    state: directory
    owner: deploy
  become: true

- name: Deploy application...
  # (copy/git/unarchive tasks)

- name: Update current symlink
  file:
    src: "/opt/releases/{{ release_version }}"
    dest: /opt/myapp/current
    state: link
    force: true
  become: true

SELinux Context

- file:
    path: /var/www/myapp
    state: directory
    setype: httpd_sys_content_t
  become: true

file Module States

StateAction
fileModify existing file attributes
directoryCreate directory (+ parents)
linkCreate symbolic link
hardCreate hard link
touchCreate empty file / update timestamp
absentDelete file or directory

Key Parameters

ParameterDescription
path / destTarget path
srcSource for links
stateDesired state
ownerFile owner
groupFile group
modePermissions (octal string)
recurseApply to contents (directories)
forceForce link creation
followFollow symlinks
access_timeSet access time
modification_timeSet modification time

FAQ

file vs copy vs template?

file manages file metadata (permissions, ownership, state). copy transfers file content. template processes Jinja2 templates. Use file when you don't need to write content.

Why use '0755' with quotes?

YAML interprets 0755 as octal number 493. Quoting '0755' passes it as a string, which Ansible correctly interprets as permission mode.

How do I create a file with content?

Use copy: content="..." instead. file: state=touch creates an empty file only.

File Module State Reference

The state parameter controls what the file module does:

StateDescriptionCreatesModifies
fileEnsure file exists with attributesNoYes (permissions, owner)
directoryCreate directory treeYesYes
touchCreate empty file or update timestampYesYes
linkCreate symbolic linkYesYes
hardCreate hard linkYesYes
absentRemove file, directory, or linkNoDeletes

Default State Behavior

When state is not specified, it defaults to file — which means the file must already exist. This is a common pitfall:

# This FAILS if /tmp/myfile doesn't exist
- ansible.builtin.file:
    path: /tmp/myfile
    mode: '0644'

# Use touch to create, then set permissions
- ansible.builtin.file:
    path: /tmp/myfile
    state: touch
    mode: '0644'

Recursive Directory Operations

Create Nested Directories

- name: Create full directory tree
  ansible.builtin.file:
    path: /opt/app/config/ssl/certs
    state: directory
    mode: '0755'
    owner: app
    group: app
  # Creates all parent directories automatically

Set Permissions Recursively

- name: Fix permissions on entire directory tree
  ansible.builtin.file:
    path: /var/www/html
    state: directory
    recurse: true
    owner: www-data
    group: www-data
    mode: '0755'

Warning: recurse: true sets the same mode on both files and directories. For different file/directory permissions, use find with command:

- name: Set directory permissions to 755
  ansible.builtin.command: find /var/www -type d -exec chmod 755 {} +

- name: Set file permissions to 644
  ansible.builtin.command: find /var/www -type f -exec chmod 644 {} +
- name: Link current release
  ansible.builtin.file:
    src: /opt/app/releases/v2.1.0
    dest: /opt/app/current
    state: link
    force: true
  # force: true overwrites existing link
- name: Relative symlink within directory
  ansible.builtin.file:
    src: ../shared/config.yml
    dest: /opt/app/current/config.yml
    state: link
- name: Find broken symlinks
  ansible.builtin.find:
    paths: /opt/app
    file_type: link
    recurse: true
  register: all_links

- name: Remove broken symlinks
  ansible.builtin.file:
    path: "{{ item.path }}"
    state: absent
  loop: "{{ all_links.files }}"
  when: not item.islnk

SELinux Context Management

- name: Set SELinux context for web content
  ansible.builtin.file:
    path: /var/www/custom
    state: directory
    setype: httpd_sys_content_t
    seuser: system_u
    serole: object_r

- name: Set SELinux context recursively
  ansible.builtin.file:
    path: /var/www/custom
    state: directory
    recurse: true
    setype: httpd_sys_rw_content_t

Temporary Files and Directories

- name: Create temporary directory
  ansible.builtin.tempfile:
    state: directory
    prefix: ansible_deploy_
  register: temp_dir

- name: Use temporary directory
  ansible.builtin.debug:
    msg: "Temp dir: {{ temp_dir.path }}"

- name: Clean up temporary directory
  ansible.builtin.file:
    path: "{{ temp_dir.path }}"
    state: absent
  when: temp_dir.path is defined

File Module vs Other Modules

TaskModuleWhy
Create empty filefile: state=touchNo content needed
Create file with contentcopy: content=...Has content
Create file from templatetemplateJinja2 variables
Modify line in filelineinfileSingle line changes
Add text blockblockinfileMulti-line blocks
Download fileget_urlFrom URL
Copy from localcopy: src=...Local to remote
Set permissions onlyfile: state=fileFile already exists
Create directoryfile: state=directoryDirectory creation
Create symlinkfile: state=linkSymbolic links

Idempotency Notes

The file module is fully idempotent:

  • state: directory — Creates only if missing, updates attributes if different
  • state: touch — Always updates modification time (reports changed every run)
  • state: absent — Only removes if exists
  • state: link — Creates or updates symlink target
Tip: Avoid state: touch in production playbooks if you don't want changed on every run. Use state: file to only set attributes on existing files.

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home