toolhq.io

All posts
6 min readby Jameel Haider

YAML multiline strings: literal, folded, and chomping indicators

YAML has two ways to write a string that spans multiple lines, and they do opposite things with newlines. The literal block | keeps every line break. The folded block > turns line breaks into spaces. Choosing the wrong one is why a shell script in your config loses its line endings, or a paragraph gets mysterious hard wraps.

The two block scalar styles

You introduce a block scalar with an indicator after the key, then indent the content:

literal: |
  line one
  line two
  line three

folded: >
  this is all
  one long
  paragraph

literal becomes the three line string line one\nline two\nline three\n. Every newline you typed is preserved. folded becomes the single line this is all one long paragraph\n, because > replaces each single line break between non empty lines with a space.

Use | when the line breaks are meaningful: shell scripts, embedded code, poetry, anything where a line is a line. Use > for flowing prose that you want to keep narrow in the source file but render as reflowed paragraphs.

How folding actually works

The fold rule has one exception that trips people up. A single newline becomes a space, but a blank line (two newlines) is preserved as an actual line break. This is what lets > represent paragraphs:

description: >
  First paragraph wrapped
  across two source lines.

  Second paragraph, kept
  separate by the blank line.

That yields two paragraphs separated by one newline, with each paragraph's internal wrapping flattened to spaces. Also, a line that is indented more than the block's base indentation is treated as literal and not folded, which is how you keep a code sample intact inside an otherwise folded block.

Chomping indicators

By default both styles keep exactly one trailing newline and discard any extra blank lines at the end. You change that with a chomping indicator placed right after the style character:

IndicatorNameTrailing newlines
(none)clipKeep exactly one
-stripKeep none
+keepKeep all trailing blank lines

So |- is a literal block with no trailing newline, and >+ is a folded block that preserves every blank line at the end. The combinations read left to right: style first, then chomping.

no_trailing_newline: |-
  exactly these bytes
keep_blank_lines: |+
  text


Use |- when the exact byte length matters, for example an API token or a value compared for equality downstream where a stray \n would cause a mismatch. Use the default clip for most text. Use + only when the trailing blanks are genuinely part of the data, which is rare.

Choosing the right one

You wantUse
A shell script or code, line breaks kept, one trailing newline|
The same but no trailing newline|-
A readable paragraph that reflows to spaces>
A short value such as a key with no trailing newline|-
Preserve every trailing blank line|+ or >+

The common mistakes

Two gotchas cause most block scalar bugs. First, indentation sets the scope: the content must be indented relative to the key, and the first non empty line fixes the indentation level for the whole block. Inconsistent indentation either errors or silently clips content. Second, people reach for > expecting it to just "allow multiple lines" and are surprised when their newlines vanish into spaces. If line breaks matter, the answer is almost always |, not >.

To confirm exactly what a block scalar parses to, including the trailing newline, convert it and read the result. The YAML to JSON converter shows the resulting string with its escapes explicit, so you can see whether that \n survived.