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 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.

Ansible Write to File: Variable Content with copy & template Modules

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. I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

See also: Ansible run_once: Execute Task on Single Host (Complete Guide)

Ansible modules: copy vs template

ansible.builtin.copy

It deals with whitespace and newlines. The quotes are important. • ansible.builtin.template

For advanced formatting or if the content contains a variable, use the 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"
The main advantage to use the Ansible copy module to Write Variable to a File is that you could write it all in one Ansible Playbook file. In this example, the parameter 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 }}
On the other hand, the Ansible module 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. I'm going to show you how to write to file a simple fruit variable using the Ansible module copy and the Ansible module template.

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 ~]$

code with ❤️ in GitHub

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

Jinja2 filters in Ansible templatesAnsible inventory complete reference

Category: troubleshooting

Watch the video: Ansible Write to File: Variable Content with copy & template Modules — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home