JSON vs YAML: Differences, Gotchas and When to Convert

YAML is a superset of JSON with indentation, comments and a few famous traps. Learn how the two map onto each other and what to check after converting.

JSON and YAML describe the same kinds of data: maps, lists, strings, numbers, booleans and null. They are used for different reasons. JSON is the language of APIs; YAML is the language of configuration files, from Kubernetes manifests to GitHub Actions workflows and docker-compose files. Sooner or later you need to move data between them.

This guide explains how the two formats relate, the YAML gotchas that bite teams in production, and what to check after converting. The JSON to YAML Converter handles quick conversions in your browser.

Origins

JSON was described by Douglas Crockford in the early 2000s and standardized as RFC 8259 and ECMA-404. Its design goal was minimalism.

YAML was started in 2001 by Clark Evans, Ingy döt Net and Oren Ben-Kiki. The name first stood for "Yet Another Markup Language", then became the recursive "YAML Ain't Markup Language" to emphasize that it is for data. Its design goal was human readability. YAML 1.2, released in 2009, was explicitly aligned so that every valid JSON document is also valid YAML.

The same data, two ways

{
  "service": "api",
  "replicas": 3,
  "debug": false,
  "ports": [80, 443],
  "env": { "LOG_LEVEL": "info" }
}
service: api
replicas: 3
debug: false
ports:
  - 80
  - 443
env:
  LOG_LEVEL: info

YAML drops the braces, brackets, commas and most quotes, and uses indentation for structure. It also allows comments with #, which is one of the main reasons people choose it for config.

Feature comparison

FeatureJSONYAML
CommentsNoYes (#)
StructureBrackets and bracesIndentation (spaces only)
Quotes on stringsAlways requiredUsually optional
Multi-line stringsEscaped \n onlyBlock scalars `
Reusing valuesNoAnchors and aliases (&, *)
Multiple documents per fileNoYes (---)
Parsing speedVery fastSlower
AmbiguityAlmost noneSome, see below

The YAML gotchas

YAML's flexibility comes from guessing types for unquoted values. That guessing is where the trouble starts.

The Norway problem

In YAML 1.1, these unquoted values are all booleans: yes, no, on, off, y, n, true, false, in various capitalizations. So this list of country codes:

countries:
  - GB
  - FR
  - NO

parses as ["GB", "FR", false]. This became known as "the Norway problem". YAML 1.2 restricted booleans to true and false, but many widely used parsers, including PyYAML by default, still follow 1.1 rules. Quote the value: - "NO".

Numbers that are not numbers

  • version: 1.10 becomes the float 1.1.
  • zip: 01234 may be read as an octal number in YAML 1.1, or lose its leading zero.
  • port: 22:22 was historically read as a base-60 number (1342) by YAML 1.1 parsers, which is why docker-compose documentation tells you to quote port mappings.
  • Long numeric IDs can lose precision.

Indentation

YAML forbids tabs for indentation. A single misaligned space can silently move a key into a different parent object rather than causing an error. Editors with YAML support and a linter such as yamllint catch most of these.

Anchors and merge keys

Anchors (&default) and aliases (*default) let you reuse blocks, and <<: merges one map into another. They are handy, but they do not exist in JSON. Converting YAML that uses them to JSON expands them into duplicated data, and converting back will not recreate them.

Converting JSON to YAML

This direction is safe in principle, since JSON's types are explicit. A good converter will:

  • Turn objects into indented maps and arrays into - lists.
  • Quote strings that would otherwise be misread, such as "no", "1.10" or strings containing : or #.
  • Keep null, true and false as YAML's equivalents.

The RedBison converter handles objects and arrays and quotes strings containing spaces. After converting, scan for string values that look like booleans or numbers and quote them if your YAML consumer uses 1.1 rules.

Converting YAML to JSON

This direction loses information:

  • Comments disappear, because JSON has nowhere to put them.
  • Anchors are expanded.
  • Multiple documents in one file need to become an array or separate files.
  • Type guesses become permanent. If the YAML parser turned NO into false, the JSON will say false.

The RedBison converter's YAML to JSON direction is built for flat key: value blocks, converting obvious numbers and booleans. For nested YAML, anchors or multi-line strings, use a full parser such as js-yaml in JavaScript, PyYAML or ruamel.yaml in Python, or yq on the command line.

Which should you use?

  • APIs and data exchange: JSON. It is unambiguous, fast and supported everywhere.
  • Config written by humans: YAML, if comments and readability matter and you lint it. Some teams prefer TOML, which has explicit types and fewer surprises.
  • Config written by programs: JSON. Generating YAML correctly is harder than it looks.

A pattern I have seen work well is to author config in YAML, validate it against a JSON Schema in CI, and convert it to JSON for the runtime. You get comments for humans and strict types for machines.

Checklist after converting

  1. Values like yes, no, on, off and country codes are quoted.
  2. Version numbers and codes with leading zeros are strings.
  3. Indentation uses spaces only.
  4. Comments you needed have been preserved somewhere.
  5. Validate the result with the tool that will read it, for example kubectl apply --dry-run=client.

Related tools

Launch JSON to YAML