Ansible Write to File: Variable Content with copy & template Modules
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
How to write variables to files in Ansible. Compare copy content vs template module, write JSON/YAML, and generate dynamic config files with examples.

How to write a variable to file with Ansible?
From a simple value or the result of complex command execution on the target node often we have the need to write the result to a file.See also: Ansible run_once: Execute Task on Single Host (Complete Guide)
Ansible modules: copy vs template
ansible.builtin.copy
ansible.builtin.template
ansible.builtin.template module.
The copy and template Ansible modules have the ability to write variables to a file.
Long story short: use the template module instead of the copy module.
Both modules write variables to a file but the template module is the safer way for advanced formatting or if the content contains a variable.
Preferred also by the early adopter of Ansible, the copy module that deals with whitespace and newlines but performs poorly with quotes and escapes contents.
On the other hand, the template module is the best option for advanced formatting or if the content contains a variable.
Ansible module copy - Write Variable to a File
- Ansible Playbook task:
- name: write to file
ansible.builtin.copy:
content: "{{ fruit }}"
dest: "/path/to/destination/file"content specifies the name of the fruit variable to be written to the dest parameter, the path of the destination file.
Ansible module template - Write Variable to a File
- Ansible Playbook task:
- name: write to file
ansible.builtin.template:
src: "mytemplate.j2"
dest: "/path/to/destination/file"- mytemplate.j2
{{ fruit }}template is the best option to write variables to a file.
Unfortunately, this module doesn't have any content parameter so you need to create a secondary template file to output the fruit variable.
As you could see in this simple example the writing to file process is started in the main Ansible Playbook file, triggering the mytemplate.j2 Jinja2 template that only output the content of the fruit variable.
The result is written to the dest, the destination file defined in the Ansible Playbook.
## Playbook How to write variables to a file with Ansible Playbook.
Ansible copy module code
---
- name: copy module Playbook
hosts: all
vars:
fruit: "banana"
output: "output.txt"
tasks:
- name: write to file
ansible.builtin.copy:
content: "{{ fruit }}"
dest: "{{ output }}"Ansible copy module execution
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory variables/write-file-copy.yml
PLAY [copy module Playbook] ***************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [write to file] ******************************************************************************
changed: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $Ansible copy module idempotency
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory variables/write-file-copy.yml
PLAY [copy module Playbook] ***************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [write to file] ******************************************************************************
ok: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $Ansible copy module before execution
ansible-pilot $ ssh devops@demo.example.com
[devops@demo ~]$ ls
[devops@demo ~]$Ansible copy module after execution
ansible-pilot $ ssh devops@demo.example.com
[devops@demo ~]$ ls
output.txt
[devops@demo ~]$ cat output.txt
banana
[devops@demo ~]$
Ansible copy module code
- write-file-template.yml
---
- name: template module Playbook
hosts: all
vars:
fruit: "apple"
output: "output.txt"
tasks:
- name: write to file
ansible.builtin.template:
src: "mytemplate.j2"
dest: "{{ output }}"
- mytemplate.j2
{{ fruit }}
Ansible copy module execution
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory variables/write-file-template.yml
PLAY [template module Playbook] ***********************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [write to file] ******************************************************************************
changed: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $
Ansible copy module idempotency
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory variables/write-file-template.yml
PLAY [template module Playbook] ***********************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [write to file] ******************************************************************************
ok: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $
Ansible copy module before execution
ansible-pilot $ ssh devops@demo.example.com
[devops@demo ~]$ ls
[devops@demo ~]$
Ansible copy module after execution
ansible-pilot $ ssh devops@demo.example.com
[devops@demo ~]$ cat output.txt
apple
[devops@demo ~]$
Conclusion
Now you know how to write variables to a file with Ansible using the copy and template modules.
See also: Ansible Create File with Content: copy Module content Parameter
Using copy (Inline Content)
- ansible.builtin.copy:
content: "{{ my_variable }}"
dest: /etc/myapp/config.txt
mode: '0644'
become: true
Using template
# Template file: templates/config.j2
# APP_NAME={{ app_name }}
# APP_PORT={{ app_port }}
# DB_HOST={{ db_host }}
- ansible.builtin.template:
src: config.j2
dest: /etc/myapp/config
become: true
See also: Add Secondary Groups to Linux Users with Ansible Playbook
Write JSON to File
- copy:
content: "{{ config_data | to_nice_json }}"
dest: /etc/myapp/config.json
become: true
Write YAML to File
- copy:
content: "{{ config_data | to_nice_yaml }}"
dest: /etc/myapp/config.yml
become: true
Write Multi-Line with Variables
- copy:
content: |
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
APP_NAME={{ app_name }}
APP_PORT={{ app_port }}
DB_HOST={{ db_host }}
DB_PORT={{ db_port }}
LOG_LEVEL={{ log_level | default('info') }}
dest: /etc/myapp/.env
mode: '0600'
become: true
Write List to File
- copy:
content: "{{ allowed_hosts | join('\n') }}\n"
dest: /etc/myapp/allowed-hosts.txt
become: true
# Or with template
# allowed_hosts.j2:
# {% for host in allowed_hosts %}
# {{ host }}
# {% endfor %}
Write Dict as Key=Value
- vars:
env_vars:
DB_HOST: db.internal
DB_PORT: "5432"
REDIS_URL: redis://cache:6379
copy:
content: |
{% for key, value in env_vars.items() %}
{{ key }}={{ value }}
{% endfor %}
dest: /etc/myapp/.env
When to Use copy vs template
Scenario Use Simple variable dump copy: content= Single variable copy: content="{{ var }}" Multi-line with logic template Loops/conditionals template JSON/YAML output copy + to_nice_json/yaml Static file copy: src= Complex config template
Write Registered Output
- command: hostname -f
register: fqdn
- copy:
content: "{{ fqdn.stdout }}\n"
dest: /etc/myapp/hostname.txt
Write Facts to File
- copy:
content: |
hostname: {{ ansible_hostname }}
ip: {{ ansible_default_ipv4.address }}
os: {{ ansible_distribution }} {{ ansible_distribution_version }}
cpu: {{ ansible_processor_vcpus }}
ram: {{ ansible_memtotal_mb }}MB
dest: /opt/myapp/host-info.txt
FAQ
copy with content vs template — performance?
copy: content= is slightly faster for simple content since Ansible doesn't need to read and process a template file. For complex configs, template is cleaner and more maintainable.
Can I append to a file?
Neither
copy nor template appends. Use lineinfile or blockinfile to add content to existing files, or shell: echo "text" >> file.
How do I write binary data?
Use
copy: src= for binary files. content: is for text only.
copy with content
- ansible.builtin.copy:
content: "{{ my_variable }}"
dest: /opt/myapp/config.txt
become: true
template Module
# Template file: templates/config.conf.j2
# server_name = {{ server_name }}
# port = {{ app_port }}
# debug = {{ debug_mode }}
- template:
src: config.conf.j2
dest: /etc/myapp/config.conf
mode: '0644'
become: true
Write JSON
- copy:
content: "{{ my_dict | to_nice_json }}"
dest: /opt/myapp/config.json
become: true
Write YAML
- copy:
content: "{{ my_dict | to_nice_yaml }}"
dest: /opt/myapp/config.yml
become: true
Write Multiple Lines
- copy:
content: |
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
SERVER_NAME={{ server_name }}
SERVER_PORT={{ app_port }}
DB_HOST={{ db_host }}
DB_NAME={{ db_name }}
dest: /opt/myapp/.env
mode: '0600'
become: true
copy vs template
Feature copy + content template Inline content ✅ ❌ (needs .j2 file) Jinja2 logic Basic {{ }} Full (loops, conditions) External file ❌ ✅ Readability Simple/short content Complex configs
template with Logic
{# templates/nginx-upstream.conf.j2 #}
upstream backend {
{% for host in groups['appservers'] %}
server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port }}{% if loop.last %};{% endif %}
{% endfor %}
}
Write Registered Output
- command: hostname -f
register: fqdn
changed_when: false
- copy:
content: "{{ fqdn.stdout }}\n"
dest: /etc/hostname-fqdn
become: true
Write from Lookup
- copy:
content: "{{ lookup('file', 'local-data.txt') }}"
dest: /opt/myapp/data.txt
- copy:
content: "{{ lookup('env', 'MY_TOKEN') }}"
dest: /opt/myapp/.token
mode: '0600'
no_log: true
FAQ
When to use copy vs template?
Use
copy + content for simple one-liners or generated data. Use template for multi-line configs with Jinja2 logic.
Does copy overwrite existing files?
Yes —
copy is idempotent but overwrites if content differs. Use force: false to skip existing files.
How to append instead of overwrite?
Use
lineinfile or blockinfile` to add content without replacing the entire file.
Related Articles
Category: troubleshooting
Watch the video: Ansible Write to File: Variable Content with copy & template Modules — Video Tutorial