JSON Compare
Paste two JSON documents to see exactly what changed, reported by path. Key order is ignored because JSON says it is insignificant; array order is respected because JSON says it matters. A text diff gets the first of those wrong.
Key order is always ignored and array order is always respected, because that is what JSON means. There is nothing to configure.
| Path | Change | Type | Original | Changed |
|---|
Runs in your browser. Nothing uploaded.
How to use it
- Paste both documents. Original on the left, changed on the right.
- Press Compare. Each difference appears with its path, both values and both types.
There is nothing to configure. Key order is always ignored and array order is always respected, because that is what JSON means — making either one an option would just be a way to get the wrong answer.
Key order does not matter. Array order does.
This asymmetry is the whole reason a text diff is the wrong tool, and it is written into the JSON specification. An object is an unordered collection of name/value pairs. An array is an ordered sequence.
| A | B | A text diff says | The truth |
|---|---|---|---|
{"a":1,"b":2} |
{"b":2,"a":1} |
different | Identical. Key order is not significant |
{"a":[1,2]} |
{"a":[2,1]} |
different | Different. Array order is significant |
{"a":1.0} |
{"a":1} |
different | Identical. JSON has one number type |
{"a":1} |
{"a":"1"} |
nearly identical | Different. Number is not string |
{"a":null} |
{"a":0} |
different | Different — and worth checking, this one breaks things |
Rows one and four are where real time gets lost. Most APIs make no promise about key order and some vary it between responses, so a text diff of two API payloads is often entirely noise. Meanwhile the change that actually broke your client — an ID that started arriving quoted — looks like almost nothing.
Types, and the bug this finds most often
The single most common real difference this surfaces is a type change. An API starts serialising numeric IDs as strings, or a boolean arrives as "true", and everything downstream that used === quietly stops matching.
Every difference reports both types, so a value change and a type change never look the same:
| Reported as | Means |
|---|---|
value changed |
Same type, different content — 1 became 2 |
number → string |
A type change. Usually a serialisation change upstream |
null → object |
A field that used to be absent now has a value, or vice versa |
object → array |
A structural change. Almost always a breaking one |
key added / key removed |
The shape changed |
Note that null gets its own type here. In JavaScript typeof null returns "object", which is a well-known wart and would make null and {} look like the same kind of thing. They are not.
Reading the paths
Paths are JSONPath-style, the same syntax jq and most JSON tooling uses.
| Path | Means |
|---|---|
$ |
The root of the document |
$.name |
The top-level name key |
$.user.address.city |
A nested key |
$.items[2].id |
The id of the third array item — arrays count from zero |
$["my key"] |
A key containing a space or dash, so it needs brackets |
Worked example
Two responses from the same endpoint, a week apart:
A: {"id": 1, "name": "Widget", "price": 9.99, "tags": ["new", "sale"]}
B: {"name": "Widget", "price": "9.99", "id": 1, "tags": ["sale", "new"]}
A text diff reports the whole line changed. What actually changed is two things:
$.price number → string 9.99 → "9.99"
$.tags[0] value changed "new" → "sale"
$.tags[1] value changed "sale" → "new"
The reordered keys — name moving before id — produce nothing, correctly. The price becoming a string is a real and probably breaking change. And the tags being reordered is reported because array order genuinely is part of the data, even though in this particular case you may not care.
Doing it in code
| Language | Approach |
|---|---|
| Python | json.load(a) == json.load(b) — dicts compare by content, so key order is handled |
| JavaScript | No deep equality built in. JSON.stringify comparison fails on key order |
| jq | jq -S . file.json sorts keys, then diff the two outputs |
| Node | require('assert').deepStrictEqual(a, b) — throws with the first difference |
The JavaScript row is the trap. JSON.stringify(a) === JSON.stringify(b) looks like a deep comparison and is really a text comparison, so it reports two identical objects as different whenever their keys were built in a different order. Sort the keys first, or compare recursively.
What this tool does not do
No JSON Patch output, no merging, no schema inference. It answers one question — what is different — and the answer is meant to be readable rather than machine-applicable.
It also compares arrays strictly by position. If you have two lists of records that are the same set in a different order, every position will report as changed. That is correct for JSON, but if what you actually have is a set rather than a sequence, list compare is the tool that treats it as one.
Related tools
The same correctness argument applies to XML compare, where attribute order is insignificant but element order is not. A JWT payload is JSON, and the JWT decoder will extract it for you before you compare two tokens. For prose or code rather than structured data, use text compare, and for Base64-encoded payloads the Base64 decoder gets you to the JSON in the first place.
Frequently asked questions
Does key order matter in JSON?
No. An object is an unordered set of name/value pairs, so {"a":1,"b":2} and {"b":2,"a":1} are the same document. Most APIs make no promise about key order and some deliberately vary it. This tool sorts keys before comparing, which is why reformatting a file produces no differences here.
Does array order matter?
Yes, and this is the important asymmetry. A JSON array is ordered, so [1,2] and [2,1] are genuinely different. Items are compared by position, and the tool reports a change at $.items[2] rather than pretending the arrays are sets.
Why is 1 different from "1"?
Because one is a number and the other is a string, and almost everything that consumes JSON treats them differently. This is one of the most common real bugs the tool surfaces: an API that started quoting its IDs. The result labels it as a type change and shows both types.
How do I read the paths?
They are JSONPath-style. $ is the root, $.user.name is a nested key, and $.items[2].id is the id of the third array item. Keys that need quoting because they contain spaces or dashes appear in brackets, like $["my key"].
Are 1.0 and 1 the same?
Yes. JSON has one number type and no distinction between integers and decimals, so 1, 1.0 and 1e0 are the same value. A text diff reports all three as different, which is a false positive you would have to check by hand.
How do I compare JSON in Python or JavaScript?
In Python, json.load both files and compare the resulting dictionaries with == — Python compares dicts by content, so key order is handled for you. In JavaScript there is no deep equality built in; comparing JSON.stringify output fails on key order, so sort the keys first or use a small recursive comparison.
Guides that use this tool
Last updated: August 16, 2026