json / diff

JSON Diff

Compare two JSON objects and see exactly what was added, removed or changed — matched by key path, not line position, so formatting and ordering don't get in the way.

~/json/diffkey-aware
OriginalReady
ChangedReady
// result

Paste JSON in both panels and click Compare.

how it works

Compared by path, not by line

A plain text diff would flag every reformatted line, even when the data is identical. This tool parses both sides and flattens them to dotted key paths — user.address.city, items[0].price — then compares those paths. Reorder the keys or change the indentation and the result stays the same; only real value differences show up.

Each row is marked + added, − removed, or shown as a remove/add pair when a value changed.

Gotcha — arrays compare by index. Element 0 is compared to element 0, and so on. If you insert an item at the start of a list, every following element looks "changed" even though the values just shifted. For ordered lists that is expected; for set-like data, sort both sides first.

worked example

A small diff, read out

// left                  // right
{ "name": "Ada",        { "name": "Ada",
  "role": "admin",        "role": "editor",
  "active": true }        "active": true,
                          "team": "core" }

A structural diff reports three things: role changed from "admin" to "editor", team was added with value "core", and name and active are unchanged. It does not care that active sits on a different line on each side — only the data is compared.

when to use it

Everyday uses

two-way vs three-way

The diff you see, and the one Git does

Comparing two objects is a two-way diff: here's the left, here's the right, here's what moved. It's perfect for "what changed between these two API responses". Merging is a harder, three-way problem, and it's what Git does behind a conflict: it looks at your version, their version, and the common ancestor all three changed from, so it can tell an edit you made from an edit they made. That's why a plain two-way comparison can't resolve a merge on its own — without the ancestor it has no way to know which side actually introduced a change versus which side just kept the original.

When you need to describe a change rather than just look at it, there are standard formats for that. JSON Patch (RFC 6902) writes a change as a list of operations — add, remove, replace at a given path — which is how a lot of REST APIs accept partial updates. JSON Merge Patch (RFC 7386) is the simpler cousin: send a small object shaped like the original, where a key set to null means "delete this". Knowing which one an API expects saves a lot of guesswork when a PATCH request quietly does nothing.

where it earns its keep

Real situations this saves you in

The everyday win is regression testing. Capture a known-good API response, run the request again after a change, and diff the two — anything that shifted is either the fix you intended or a bug you just shipped. The same move catches config drift: dump the configuration from staging and production side by side, and the diff is the short list of settings that explain why one environment behaves and the other doesn't. It also makes code review of generated files bearable, since a structural diff ignores the reformatting and key reordering that a line-based diff would drown you in.

faq
Can I turn a diff into a PATCH request body?

Yes — that's essentially what JSON Patch is for. Once you know which fields changed, you can express just those changes as add/remove/replace operations and send them, instead of re-sending the whole object. Check whether the API expects JSON Patch or the simpler Merge Patch.

What's the difference between JSON Patch and JSON Merge Patch?

JSON Patch (RFC 6902) is an explicit list of operations (add/remove/replace at a path). JSON Merge Patch (RFC 7386) is a partial object that mirrors the original, where null means delete. Patch is more precise; Merge Patch is simpler for shallow updates.

Can it compare deeply nested objects and arrays of objects?

Yes. A structural diff walks the whole tree, comparing nested objects key by key at every level. Arrays of objects are matched by position, so if order is not meaningful, sort both sides on a stable key first to avoid spurious "changed" rows.

Does the key order matter?

No. Because comparison is by key path, {"a":1,"b":2} and {"b":2,"a":1} are reported as identical.

Can I paste large objects?

Yes, within reason — everything runs in your browser, so very large files (multi-megabyte) depend on your device's memory. Nothing is uploaded.

What counts as "changed"?

The same key path existing on both sides with a different value. It is shown as the old value removed and the new value added, so you can read the before and after.