What Is YAML - Differences from JSON and Basic Syntax

YAML (YAML Ain't Markup Language) is a data language designed above all to be easy for people to read and write. Most of the configuration files you meet in modern development, from Kubernetes to GitHub Actions and Docker Compose, are written in YAML. This article walks through how it differs from JSON, the basic syntax of indentation, lists, maps, multi-line strings, and anchors, and where to use it, with example code and common pitfalls.

In short: YAML is JSON's human-friendly relative that expresses structure with indentation. You get comments and can drop most quotes and braces, but an indentation mistake becomes a structural mistake, so it pays to learn the rules precisely.

1. What YAML is

YAML is a data serialization language that first appeared in 2001; the current specification is YAML 1.2 (revision 1.2.2, published in 2021). The name is a recursive acronym for "YAML Ain't Markup Language": it is meant for describing configuration and data structures, not for document markup like HTML. Files use the .yaml or .yml extension.

The data structures it can express are the same as JSON's: combinations of scalars (strings, numbers, booleans, null), sequences (lists), and mappings (keys and values). As a result, almost anything written in YAML converts directly to JSON.

2. Differences from JSON

The biggest difference is who the notation is for. JSON is a minimal syntax aimed at data exchange between programs, while YAML is aimed at people editing files by hand.

AspectYAMLJSON
Expressing structureIndentation (spaces only)Braces {} and brackets []
CommentsWritten with #Not available
Quoting stringsUsually optionalRequired (double quotes)
Multi-line stringsNatural with | and >Escaped with \n
Reusing valuesAnchors & / aliases *None
Main usesConfiguration files (CI, IaC, and so on)APIs and data exchange

YAML 1.2 is designed to treat JSON almost as a subset, so most valid JSON documents can be read directly by a YAML parser. Our CSV versus JSON article also touches on choosing between formats.

3. Basic syntax - maps, lists, and nesting

Keys and values are written as key: value (always a space after the colon), and list items start with - (a hyphen followed by a space). Hierarchy is expressed with indentation, customarily two spaces. Tabs are not allowed.

# Comments are allowed (a big difference from JSON)
name: sample-app        # strings usually need no quotes
version: "1.2"          # quote it to keep it a string, not a number
debug: false            # booleans are true / false
services:               # a nested list
  - name: web
    port: 8080
  - name: db
    port: 5432
database:               # a nested map
  host: localhost
  options:
    pool: 10

Converted to JSON this becomes the following. The same structure is written in YAML without quotes or braces.

{
  "name": "sample-app",
  "version": "1.2",
  "debug": false,
  "services": [
    { "name": "web", "port": 8080 },
    { "name": "db", "port": 5432 }
  ],
  "database": { "host": "localhost", "options": { "pool": 10 } }
}

4. Multi-line strings - | and >

Strings containing line breaks are written with block scalars. | (literal) keeps the line breaks as they are, while > (folded) converts line breaks into spaces, joining the text into one line. | suits embedded scripts, and > suits long descriptions.

script: |
  echo "line one"
  echo "line two"     # line breaks are preserved

summary: >
  This text is folded
  into a single line.   # line breaks become spaces

5. Anchors and aliases - reusing values

When you want to repeat the same value, mark it with &name (an anchor) and reference it with *name (an alias). Combined with <<: (the merge key), you can inherit the contents of a map and override only part of it. This is handy for reducing duplication in CI configuration.

defaults: &defaults
  retries: 3
  timeout: 30

production:
  <<: *defaults      # pull in the contents of defaults
  timeout: 60        # override only timeout

staging:
  <<: *defaults

JSON has no such mechanism, so converting YAML to JSON expands aliases into the actual values.

6. Where to use it, and pitfalls

YAML dominates the space of "configuration files that people read, write, and review": Kubernetes manifests, CI configuration for GitHub Actions or CircleCI, Docker Compose, Ansible playbooks, and OpenAPI definitions. Conversely, for data exchange between programs and web API responses, JSON, with its small and fast-to-parse specification, is the standard (see What Is JSON).

When writing YAML, watch out for these three points.

7. Try it yourself

Seeing what JSON your YAML turns into is the fastest way to understand the structure. Paste YAML into the converter below and it is converted to JSON on the spot, with syntax errors reported by line number. The reverse direction (JSON to YAML) works too.

Free Tool Try the YAML / JSON converter Convert between YAML and JSON in both directions. Syntax errors are shown with line and column numbers, and the indent width is selectable. Everything runs in your browser.

8. References

This article draws on the following primary sources. See them for the full specification.

Frequently asked questions (FAQ)

Should I use YAML or JSON?

YAML suits configuration files that people read and edit, because it supports comments and needs few symbols. JSON suits data exchange between programs, because its specification is small and unambiguous. YAML 1.2 treats JSON almost as a subset, so most valid JSON documents can be read directly as YAML.

Can I indent YAML with tabs?

No. The YAML specification allows only spaces for indentation, and using a tab character causes a syntax error. Configuring your editor to expand tabs into spaces prevents this. Two spaces is the customary width, and indentation at the same level must be aligned.

What is the "Norway problem"?

It is the nickname for a quirk of the older YAML 1.1 specification, where values such as no, yes, on, and off are interpreted as booleans, so the country code NO (Norway) unexpectedly becomes false. YAML 1.2 fixed this by limiting booleans to true and false, but YAML 1.1 parsers are still in active use, so it is safest to quote ambiguous values as "NO".

← Back to all blog posts