json:yaml

YAML multiline strings

YAML has two block scalar styles and two chomping modifiers, and one of those combinations is quietly breaking your API key.

Four ways to write a multi-line string

YAML has two block scalar styles and two chomping modifiers, giving four combinations. The choice controls two independent things: whether internal newlines are kept, and what happens to the newline at the end.

SyntaxInternal newlinesTrailing newlineUse for
|KeptOne keptScripts, certificates, log samples
|-KeptStrippedKeys and tokens that must not end in a newline
|+KeptAll keptRare; when trailing blank lines are significant
>Folded to spacesOne keptLong prose wrapped for readability
>-Folded to spacesStrippedA long single-line value, wrapped in the source

Literal style: |

Every line break in the block is a line break in the value. This is what you want whenever the newlines are part of the data.

startup: |
  #!/bin/sh
  set -eu
  echo "starting"
  exec /usr/bin/app

Produces: "#!/bin/sh\nset -eu\necho \"starting\"\nexec /usr/bin/app\n"

The indentation of the block is stripped — the parser removes the common leading whitespace, so the script does not arrive with two spaces on every line. Extra indentation beyond the common level is preserved, which is how you keep the shape of indented code.

Folded style: >

Single line breaks become spaces. Blank lines become a single line break. Use it to wrap a long sentence in the source file without putting line breaks in the value.

description: >
  This service handles checkout requests
  and writes them to the order queue.

  It retries failed writes three times.

Produces: "This service handles checkout requests and writes them to the order queue.\nIt retries failed writes three times.\n"

A line that is indented more than the rest of the block is not folded — it keeps its line breaks. This surprises people who indent a bullet list inside a folded block, and it is occasionally useful.

Chomping: the - and + modifiers

By default a block scalar ends with exactly one newline, regardless of how many blank lines follow it. That default is right most of the time and wrong in one important case: secrets.

api_key: |
  sk_live_4eC39Hq...     # value ends with "\n" — many APIs reject this

api_key: |-
  sk_live_4eC39Hq...     # no trailing newline — usually what you want

An authentication failure that makes no sense, on a key you have triple-checked, is very often a trailing newline from a | block that should have been |-.

What happens on conversion to JSON

You can see this for yourself by pasting a block scalar into YAML to JSON. All four styles collapse to one JSON string with \n escapes. The distinction between literal and folded exists only in the YAML source — by the time the document is parsed, there is just a string. Converting JSON back to YAML will not restore your block style; the value comes back as a quoted string with escapes, which is correct and much harder to read.

Questions people ask

What is the difference between | and > in YAML?
The pipe keeps every line break as a line break. The angle bracket folds single line breaks into spaces, so the value ends up as one long line. Use the pipe for scripts and certificates, the angle bracket for prose wrapped in the source.
What does the minus in |- do?
It strips the trailing newline. By default a block scalar ends with exactly one newline, which many APIs reject on a key or token. If authentication fails on a credential you have triple-checked, this is usually why.
Is the block indentation included in the value?
No. The common leading whitespace is stripped. Indentation beyond that common level is preserved, which is how indented code keeps its shape.
What happens to block scalars when I convert to JSON?
They collapse into a single JSON string with escaped newlines. The distinction between literal and folded exists only in the YAML source, and converting back will not restore it.