YAML Cheatsheet

JSON Compatibility

Use this YAML reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Every JSON document is valid YAML 1.2

YAML 1.2 was rewritten specifically to make JSON a strict subset. A .json file can be renamed .yaml and parsed unchanged.

{"name": "api", "replicas": 3, "tags": ["web", "prod"],
 "limits": {"cpu": "500m"}, "debug": false, "extra": null}

Feed that exact text to yaml.safe_load and you get the same Python object json.loads gives, == and all. That is because JSON is just YAML flow style with mandatory quoting and no trailing commas.

JSON pasted inside YAML

Since flow style is legal anywhere a value is, a JSON blob drops straight into a YAML file with no reformatting.

service: api
config: {"retries": 3, "hosts": ["a", "b"], "debug": false}
annotations:
  checksum/config: abc123
  scheduler.alpha.kubernetes.io/tolerations: |
    [{"key": "dedicated", "operator": "Equal", "value": "gpu"}]

config parses to {'retries': 3, 'hosts': ['a', 'b'], 'debug': False}. The tolerations line is different on purpose: that annotation's value must be a string containing JSON, so it goes in a | block. Kubernetes annotations are map[string]string, so any structured value has to be stringified.

The flow-style equivalence

YAML blockYAML flowJSON
a: 1{a: 1}{"a": 1}
a: - 1 - 2{a: [1, 2]}{"a": [1, 2]}
a: b: 1{a: {b: 1}}{"a": {"b": 1}}
a:{a: null}{"a": null}
(none)[][]

What YAML relaxes on top of JSON:

  • Keys need no quotes.
  • Trailing commas are allowed: [1, 2, 3,].
  • Comments are allowed inside flow collections.
  • null, ~, and an omitted value are all null.

What YAML adds that JSON has no answer for

FeatureYAMLJSON
comments#none
multi-line strings| and > blocks"a\nb" only
references&a / *anone
inheritance<<: *basenone
several docs in one file---none, or NDJSON
dates as a type2024-01-15string only
non-string keys1: xkeys are always strings
explicit types!!str 42none
trailing commasallowedforbidden
NaN and Infinity.nan, .infnot in the spec
indentation mattersyesno

Converting between them

# YAML -> JSON
yq -o=json '.' config.yaml
python -c "import yaml,json,sys; \
  print(json.dumps(yaml.safe_load(sys.stdin), default=str))" < config.yaml

# JSON -> YAML
yq -P '.' data.json
python -c "import yaml,json,sys; \
  print(yaml.safe_dump(json.load(sys.stdin), sort_keys=False))" < data.json

# every doc in a multi-doc stream, as one JSON array
yq -o=json eval-all '[.]' manifests.yaml

Two things break a naive YAML-to-JSON conversion:

- Dates. 2024-01-15 loads as a datetime.date, which json.dumps refuses with TypeError: Object of type date is not JSON serializable. Hence default=str above. - Non-string keys. {1: "x"} or {True: "x"} becomes {"1": "x"} in JSON, silently changing the key's type. A round trip is not lossless.

Also lost in a round trip: comments, anchors, the choice of block versus flow style, and key order unless you pass sort_keys=False.

Choosing between them

UseFormat
human-edited configYAML or TOML
API request and response bodiesJSON
machine-to-machineJSON
a config with repeated blocksYAML, for <<: *base
a config a program writes back outJSON, no comments to lose
logs, one record per lineNDJSON
something untrusted users submitJSON, far smaller attack surface

YAML's superset relationship means a JSON parser is the safest way to read a file you know is JSON. Reading it with a YAML parser adds the whole type resolver, the alias expander, and, if you slip and call yaml.load, arbitrary object construction. Use the narrower parser when you can.