JSON Diff

Compare two JSON documents structurally — added, removed and changed keys with values, by nested path.

Paste an original JSON document and a changed copy — a config before/after, two API responses, a fixture and the data a service actually returned — and the diff walks both structures in parallel. Every added, removed and changed key is reported by its nested JSONPath ($.server.host, $.features[2]) with its old and new value, in a side-by-side view or a unified change list you can filter, copy and export. Key order never matters; only structure and values do.

🔒 100% private — nothing is uploaded or stored. Both documents are parsed and compared entirely in your browser with plain JavaScript. Your JSON — config files, API responses, anything you paste — never touches our servers, is never written to disk, and the page keeps working even if your internet connection drops.

Document A (original)

empty

Document B (changed)

empty

Tip: press Ctrl+Enter (or ⌘+Enter) in either box to run the diff. The diff also runs live as you type.

Paste two JSON documents above — the diff runs as you type.

Nothing to show yet — load a sample or paste your own JSON.

Why structural, not textual

A plain text diff (diff, git diff) compares characters. That is the wrong lens for JSON: reordering the keys of an object, or reformatting whitespace, produces a wall of noise even though nothing changed; and a single value change deep in a 200-line document shows the whole region as different, with no idea which key actually moved. A structural diff parses both documents into values first, then walks them in parallel — so the report contains exactly the keys that were added, removed or changed, each named by its path rather than its line number. Reformatting or reordering keys in either document changes nothing about the result.

Reading the paths

Each change is addressed with JSONPath-style notation, so you can jump straight to the key in your code or config:

PathMeaning
$The root of the document
$.server.hostThe key host inside the object server
$.features[2]The third element of the array features (zero-based)
$.user.settings.notifications.smsA deeply nested key, one segment per level

Arrays: order matters — unless you say otherwise

By default arrays are compared element by element, by index: [1, 2, 3] vs [3, 2, 1] reports three changed elements, because position [0] changed from 1 to 3 and so on. That is the right answer when your array is ordered (a ranked list, a timeline). When your array is an unordered collection — a set of tags, a list of deployment targets — tick Ignore array order and elements are matched by value instead: a pure reorder then reports no changes at all. An element that was modified (not just moved) is matched to its closest counterpart and reported as a single change at its new index, with the old and new values side by side; only elements with no counterpart at all are reported as added or removed.

Type changes

If a key holds a number in one document and a string in the other — 5 vs "5" — the value differs, and the tool flags it as a type change with its own badge. This is one of the most common API regressions in practice (a number serialised as a string after a backend change) and it is easy to miss in a wall of text, which is exactly why it gets called out separately in the stats and the change list.

Nothing on this page leaves your browser: there is no server round-trip when you paste, diff or copy, no analytics on your inputs, and no storage of any kind.


Luke Keam
Thank you for reading. Get in touch
Luke Keam | techgeek.biz