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.
Document A (original)
emptyDocument B (changed)
emptyTip: press Ctrl+Enter (or ⌘+Enter) in either box to run the diff. The diff also runs live as you type.
Nothing to show yet — load a sample or paste your own JSON.
Nothing to show yet.
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:
| Path | Meaning |
|---|---|
$ | The root of the document |
$.server.host | The key host inside the object server |
$.features[2] | The third element of the array features (zero-based) |
$.user.settings.notifications.sms | A 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.