Quick answer
A JSON diff compares two documents by their data rather than their text, so formatting and key order never show up as changes. Paste the original and the new version side by side into Playxoft's free JSON Diff tool: every difference is listed with its path and marked as added, removed, changed or type changed. You can ignore array order, allow a numeric tolerance and export an RFC 6902 JSON Patch.
- Structural comparison
- Added, removed and changed
- Path for every change
- Ignore key or array order
- Numeric tolerance
- JSON Patch export
- Click to jump
How to use the JSON Diff
- 1Paste the original JSON into Original (A) and the new version into Modified (B), or drop a file onto each.
- 2Keep Ignore key order on unless the order of keys matters to you.
- 3Turn on Ignore array order for lists that are really sets, and Numeric tolerance to ignore floating-point noise.
- 4Click a summary chip to filter by Added, Removed, Changed or Type changed, and click any row to jump to it.
- 5Copy the plain-text report, or Copy JSON Patch to apply the same change in code.
Why not use a text diff for JSON?
Line-based tools like git diff compare characters, not data. Re-indenting a file, reordering keys or minifying it produces a wall of red and green even though nothing meaningful changed, while a real change buried in a long line is easy to miss.
A structural diff parses both documents first and compares values. Formatting is irrelevant, 1.0 equals 1, and each change is reported once, with the path to it:
~ $.version: "1.8.2" → "1.9.0"
~ $.replicas: 3 → "3" (type changed: number → string)
- $.timeoutMs: 2500
+ $.owners[2]: {"id": 3, "name": "Grace", "role": "dev"}Paths use JSONPath-style notation: $ is the root, .name is a key and [2] is an array index. Keys that aren't plain identifiers are written in brackets, as in $["first name"]. Click any change in the list to jump to it in the editor.
How are changes inside arrays matched up?
Arrays are where naive diff tools fall apart. Compare items index by index, and inserting one element at the top makes every later index look changed.
This tool aligns arrays with a longest-common-subsequence pass, the same idea behind diff itself, so an insertion reads as one addition and a deletion as one removal. Items that were edited rather than added or removed are then paired up: objects that share an id, _id, uuid, key or slug value are matched first, then the most similar remaining objects.
The result reads the way you would describe it to a colleague: "Alan's role changed and Grace was added", not "owners 1 to 40 differ". Integers beyond 2^53 are compared digit for digit, so two IDs that JavaScript would round to the same number are still reported as different.
Does key order or array order matter in JSON?
Key order doesn't. RFC 8259 defines an object as an unordered collection of name/value pairs, so {"a": 1, "b": 2} and {"b": 2, "a": 1} are the same data, and Ignore key order is on by default. Turn it off when order matters to you, for example in a hand-maintained config file, and moved keys are listed as reordered.
Array order does matter: [1, 2] and [2, 1] are different values. But many arrays are really sets, such as tags, roles, permissions and feature flags. Ignore array order compares those as unordered collections, so only items that were genuinely added or removed are reported.
| Option | Use it when |
|---|---|
| Ignore key order (on by default) | Almost always |
| Ignore array order | Arrays are sets: tags, IDs, permissions |
| Numeric tolerance | Floats come from different runtimes or rounding |
What is a JSON Patch?
JSON Patch (RFC 6902) is a standard format for describing changes to a JSON document as a list of operations. Each operation names its target with a JSON Pointer (RFC 6901), where / separates segments, ~1 stands for a slash inside a key and ~0 for a tilde:
[
{ "op": "replace", "path": "/version", "value": "1.9.0" },
{ "op": "remove", "path": "/timeoutMs" },
{ "op": "add", "path": "/owners/2", "value": { "id": 3, "name": "Grace" } }
]Copy JSON Patch produces a patch that turns A into B, ordered so that every array index is valid at the moment its operation runs. Apply it with fast-json-patch in JavaScript or jsonpatch in Python, or send it as an HTTP PATCH body with the application/json-patch+json media type.
The simpler JSON Merge Patch (RFC 7396) sends a partial document instead. It is easier to read, but it can't set a value to null (null means delete) or change a single array element.
How do I diff JSON on the command line or in code?
Normalize both files with jq, then use an ordinary diff. Sorting keys with -S removes key-order noise:
diff <(jq -S . a.json) <(jq -S . b.json)In code, fast-json-patch (JavaScript) and jsonpatch (Python) generate RFC 6902 patches from two documents, which also makes a precise assertion in API regression tests. For a quick visual check, paste both documents here: nothing is uploaded, so it is safe for production data. If one side won't parse, the JSON Validator lists every error in it.
Frequently asked questions
Last updated by the Playxoft engineering team.