YAML and JSON Diff
Paste two configs and see what actually changed between them. It runs entirely in your browser, and it compares the data rather than the text — so reformatting a file is not a difference.
Why a text diff is the wrong tool for YAML
git diff compares lines, which is exactly right for code and quietly wrong for configuration. YAML can spell the same value many ways, so a line differ reports a pile of changes that mean nothing — and buries the one that does.
This page parses both sides first. Everything below normalises away before the comparison, and none of it is ever reported as a change:
- Key order
- name before port, or port before name — same data either way.
- Quoting style
web,"web"and‘web’are one value.- Flow vs block
- A list written inline or on its own lines is the same list.
- Anchors and aliases
- An anchor is compared as the value it expands to.
- Comments and blank lines
- Neither carries data, so neither is a difference.
- Indent width
- Two spaces or four, the structure is what is compared.
List items are matched by name, not by position
This is the single biggest difference on a Kubernetes manifest. Insert one container at the top of a list and a positional differ reports every container below it as rewritten, because everything shifted down by one. Nothing was rewritten — one thing was added.
When every item in a list carries a name, id,key, path or host that is unique on both sides, items are paired by that field instead. So an inserted container reads as one addition, and a changed image reads as one change atspec.template.spec.containers[name=web].image — the path you would use to talk about it.
When there is no such field — a list of ports, a list of strings — items are compared by position, because that is genuinely all the information there is.
Type changes are called out separately
replicas: 3 and replicas: "3" look almost identical in a text diff — one pair of quotes — and they are the kind of change that gets an apply rejected. When a value changes type as well as content, the row is markedtype changed so it does not read as a cosmetic edit.
The YAML version selector matters here for the same reason it does on the converter: under YAML 1.1 NO is the boolean false and under 1.2 it is the string "NO". Both sides are always read with the same version, so the setting can never invent a difference that is not there — but it does decide what type a value has.
When you need this
- Reviewing what a template rendered. Run
helm templatebefore and after a values change and compare the output to see what the change really did. - Comparing environments. A staging and a production manifest that should differ in three places and probably differ in nine.
- Checking a tool did not reformat your file. Many YAML libraries rewrite quoting and key order on save. This tells you whether anything but the formatting moved.
- Comparing across formats. One side YAML and the other JSON is fine — both normalise to the same value before they are compared.
Doing it on the command line
For anything scripted, dyff is the closest equivalent, and normalising with yq before a plain diffgets most of the way there.
dyff between old.yaml new.yaml
# or normalise first, then use any diff tool
diff <(yq -o=json -P 'sort_keys(..)' old.yaml) \
<(yq -o=json -P 'sort_keys(..)' new.yaml)