Ansible Multiline Strings: YAML Block Scalars | and > (Complete Guide)
By Luca Berton · Published 2026-04-03 · Category: installation
How to write multiline strings in Ansible YAML. Literal block (|), folded block (>), chomp indicators, and practical examples for shell commands and templates.
Working with multiline strings in Ansible playbooks is common but the YAML syntax can be confusing. This guide explains every multiline option with clear examples.
Literal Block Scalar: | (Keep Newlines)
The | character preserves newlines exactly as written:
- name: Run multi-line script
ansible.builtin.shell: |
echo "Step 1: Update packages"
apt-get update
apt-get upgrade -y
echo "Step 2: Restart service"
systemctl restart nginx
Each line becomes a separate line in the output. A trailing newline is added.
See also: Ansible troubleshooting - Error parser-error
Folded Block Scalar: > (Join Lines)
The > character joins lines with spaces (like a paragraph):
- name: Long description
ansible.builtin.debug:
msg: >
This is a very long message that
spans multiple lines in the YAML file
but will be rendered as a single
paragraph with spaces.
Output: This is a very long message that spans multiple lines in the YAML file but will be rendered as a single paragraph with spaces.\n
Chomp Indicators: Strip Trailing Newlines
|- Strip trailing newline
vars:
greeting: |-
Hello
World
# greeting = "Hello\nWorld" (no trailing newline)
|+ Keep all trailing newlines
vars:
greeting: |+
Hello
World
# greeting = "Hello\nWorld\n\n" (keeps blank line)
>- Fold and strip
vars:
query: >-
SELECT *
FROM users
WHERE active = true
ORDER BY name
# query = "SELECT * FROM users WHERE active = true ORDER BY name"
>- is the most common for inline strings — folds to one line, no trailing newline.
See also: Ansible check_mode: Dry Run & Test Playbooks Without Making Changes
Summary Table
| Syntax | Newlines | Trailing | Use Case |
|--------|----------|----------|----------|
| | | Kept | Single \n | Shell scripts |
| |+ | Kept | All kept | Preserving whitespace |
| |- | Kept | Stripped | Clean multiline strings |
| > | Folded | Single \n | Long descriptions |
| >+ | Folded | All kept | Rare |
| >- | Folded | Stripped | SQL queries, URLs, commands |
Common Use Cases
Shell scripts
- name: Deploy script
ansible.builtin.shell: |
set -euo pipefail
cd /opt/app
git pull origin main
pip install -r requirements.txt
systemctl restart myapp
args:
executable: /bin/bash
Long when conditions
- name: Complex condition
ansible.builtin.debug:
msg: "Conditions met"
when: >-
(ansible_os_family == 'Debian' and
ansible_distribution_major_version | int >= 11) or
(ansible_os_family == 'RedHat' and
ansible_distribution_major_version | int >= 9)
SQL queries
- name: Run database query
community.postgresql.postgresql_query:
query: >-
SELECT u.name, u.email, COUNT(o.id) as orders
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.active = true
GROUP BY u.name, u.email
ORDER BY orders DESC
LIMIT 10
File content
- name: Create config file
ansible.builtin.copy:
content: |
# Application Configuration
app_name: MyApp
debug: false
database:
host: db.example.com
port: 5432
dest: /etc/myapp/config.yml
Debug messages
- name: Multi-line debug message
ansible.builtin.debug:
msg: |-
=== Deployment Summary ===
Host: {{ inventory_hostname }}
Version: {{ app_version }}
Environment: {{ env }}
Status: SUCCESS
See also: Ansible when Conditional: Complete Guide with Examples
Jinja2 Multiline
- name: Template with multiline
ansible.builtin.template:
src: template.j2
dest: /etc/myapp/hosts
vars:
servers:
- 10.0.1.1
- 10.0.1.2
# template.j2:
# {% for server in servers %}
# {{ server }}
# {% endfor %}
FAQ
When should I use | vs >?
Use | (literal) when newlines matter (scripts, config files). Use > (folded) when you want one continuous string (messages, queries, conditions).
Why is my multiline string getting a trailing newline?
By default, both | and > add a trailing newline. Use |- or >- to strip it.
How do I indent content inside a literal block?
The first line's indentation sets the base. All subsequent lines are relative to that base:
content: |
line 1 (base indent)
indented line (2 extra spaces preserved)
back to base
Literal Block (|) — Preserves Newlines
- name: Run multi-line script
ansible.builtin.shell: |
echo "Step 1: Update"
apt update
apt upgrade -y
echo "Step 2: Install"
apt install -y nginx
become: true
Folded Block (>) — Joins Lines
- name: Long command on multiple lines
ansible.builtin.debug:
msg: >
This is a very long message
that spans multiple lines
but will be joined into
a single line with spaces.
# Output: "This is a very long message that spans..."
Comparison
| Syntax | Newlines | Trailing Newline |
|--------|----------|-----------------|
| | | Preserved | Yes (one) |
| > | Folded to spaces | Yes (one) |
| |- | Preserved | No |
| >- | Folded | No |
| |+ | Preserved | All kept |
| >+ | Folded | All kept |
Chomp Indicators
# Strip trailing newline
msg: |-
line one
line two
# Result: "line one\nline two" (no trailing \n)
# Keep trailing newline (default)
msg: |
line one
line two
# Result: "line one\nline two\n"
# Keep ALL trailing newlines
msg: |+
line one
line two
# Result: "line one\nline two\n\n\n"
Shell Commands
# Most common: | for multi-line shell
- shell: |
cd /opt/myapp
git pull origin main
pip install -r requirements.txt
systemctl restart myapp
# Folded for single long command
- command: >-
docker run
--name myapp
-p 8080:8080
-v /data:/data
-e DB_HOST=localhost
myapp:latest
Variables in Multiline
- copy:
content: |
[app]
name={{ app_name }}
port={{ app_port }}
host={{ ansible_host }}
env={{ app_env }}
dest: /etc/myapp/config.ini
Template Content
- copy:
content: |
server {
listen 80;
server_name {{ domain }};
root {{ document_root }};
}
dest: /etc/nginx/sites-available/{{ domain }}
become: true
In Variables
vars:
welcome_message: |
Welcome to {{ inventory_hostname }}!
Environment: {{ app_env }}
Last deployed: {{ ansible_date_time.iso8601 }}
long_description: >
This application provides
a web interface for managing
infrastructure automation tasks.
Jinja2 in Multiline
- debug:
msg: |
{% for host in groups['webservers'] %}
Server: {{ host }} ({{ hostvars[host].ansible_host }})
{% endfor %}
FAQ
When to use | vs >?
•| (literal): Shell scripts, config files, any content where newlines matter
• > (folded): Long sentences, descriptions, single-line commands split for readability
Why does my shell script fail with >?
> folds lines into one. Shell commands need | to preserve line breaks as separate commands.
How do I include empty lines in |?
Just leave blank lines — they're preserved:
msg: |
First paragraph.
Second paragraph after blank line.
Related Articles
• Jinja2 filters in Ansible templates • Ansible Multiline Strings Guide • conditional execution with Ansible when • the Ansible inventory deep-dive • Ansible privilege escalation patternsCategory: installation