ToyTools Guide
How to Compare Two JSON Documents
See how a structural JSON diff names added, removed, and changed paths, and why key order and 1 versus 1.0 are not changes.
Quick Answer
A JSON diff is a structural compare of two JSON documents. Paste the left value and the right value. The page parses both, then names the paths that were added, removed, or changed. Object key order does not count. Array order does. The number 1 and the number 1.0 are equal. A string, a boolean, and null are compared exactly.
This is not a line diff and it does not pretty-print. If either side is not valid JSON, the page says which side and prints the parse error. It does not invent a diff. If both panes are empty, the page stays quiet. Runs entirely on your device. Nothing is uploaded.
Use it when you are comparing two API responses before and after a deploy, checking a config file after an editor reordered keys, or reviewing a payload two services claim is the same. Spotting an array that one side sorted is the same job.
Compare two JSON documentsHow does a JSON diff work?
How does the comparison actually run? It works by parsing, then walking. JSON.parse reads each pane. The walk starts at the root. When both sides are objects, keys are matched by name. When both sides are arrays, indexes are matched by position. Everything else is one changed path, including a type swap such as an object becoming an array.
A path uses a dot for a plain key and brackets for an index or an awkward key. user.email is a field. tags[0] is the first array element. ["a.b"] is a key that itself contains a dot, so a dot path would be a lie. The line starts with added, removed, or changed, then the path, then the value JSON.stringify would print.
For example, the left document is {"id":1,"name":"Ada","tags":["a","b"]} and the right document is {"name":"Ada","id":1.0,"tags":["b","a"],"role":"admin"}. id is equal because both numbers are 1. name is equal. tags[0] changed from "a" to "b", tags[1] changed from "b" to "a", and role was added. Key order between name and id is ignored.
Why does object key order not count?
Because a JSON object is a map. The specification does not give keys an order that affects meaning. {"b":1,"a":2} and {"a":2,"b":1} parse to the same value. Pretty printers, JSON.stringify, and many editors still rewrite the order, and a text diff then reports every line as edited. The values did not change. Calling that a data change is the common mistake of treating reordered object keys as a data change.
The verification line exists for that case. When the characters differ and the parsed values do not, the page says the text differs and the values match. It names the usual reasons: key order, spacing, and 1 versus 1.0. When the two pastes are already the same characters, that sentence stays quiet and the status is simply that there are no differences. Silence is the point. A match that is already obvious does not need a lecture.
Checking a config file after an editor reordered keys is the everyday version. You wanted to know whether a setting changed. The editor also sorted the file. A line diff cannot tell those apart. A structural diff can, because the walk never sees key order.
When does array order count?
Array order counts because arrays are ordered. [1,2] and [2,1] are different JSON values. The walk compares index 0 with index 0. You see two changed paths, not a shrug that says the arrays differ. An extra tail element is added at that index. A missing tail element is removed. Spotting an array that one side sorted is this rule in a real file: the items may all still be present, and the indexes still moved.
Objects inside an array are walked too. items[0].qty changed from 1 to 2 is more useful than reprinting items[0]. If the types disagree at an index, the walk stops at that path. changed items[0] from an object to a string is one line. Inventing child removals inside a value the other side does not have would be a story, not a diff.
Nested object key order still does not count. {"a":1,"b":2} at items[0] matches {"b":2,"a":1} at items[0]. Only the array position is ordered. That split is the reason a single rule of "order never matters" fails this data. Objects and arrays are not the same kind of container.
Why are 1 and 1.0 the same number?
JSON.parse reads both tokens as the number 1. Numeric comparison then uses equality, so 1 and 1.0 match. The source text still differs, which is why the values-match line can appear. Treating 1 and 1.0 as different numbers is the mistake a line diff makes, and it is the mistake this page refuses.
Strings, booleans, and null stay strict. "1" is not 1. true is not 1. null is not 0 and it is not false. For example, changed qty: 1 to "1" means one service quoted the field. Reviewing a payload two services claim is the same often ends on exactly that line: the shape looks right, the type is not.
Very large integers are a limit of the parser, not a clever equality. JavaScript numbers cannot tell 9007199254740993 from 9007199254740992. Both become the same value before the walk starts. If those digits matter, quote them as strings. A one-character difference in a string is then a real change. The page will not pretend otherwise.
What if one side is not valid JSON?
The page names the side and the parse error. Left is not valid JSON, or Right is not valid JSON, followed by the message JSON.parse produced. If both fail, both sentences appear. The path list stays empty. Showing a partial diff against a value that never parsed would be guessing.
Both panes blank is not an error. One pane blank is, because an empty string is not JSON. A trailing comma, a single quote, a comment, and a trailing note from a log line all fail the same way. This page does not repair them. The JSON formatter will offer a repair for a trailing comma or a smart quote. The JSON validator reports one document. Use those when the job is syntax. Come back here when both sides parse.
What mistakes does a text diff make?
A text diff compares lines. Indentation, key order, and numeric spelling all look like edits. A real change, such as flags[2] flipping, sits in that noise. People then edit the wrong file, or they re-send a payload that was already correct. The first mistake is treating reordered object keys as a data change. The second is treating 1 and 1.0 as different numbers.
The third mistake is uploading private JSON to a server-side comparison site. Tokens, customer records, and environment files are routine in these pastes. Runs entirely on your device. Nothing is uploaded. Open the network panel while you paste if you want to see the absence of a request. The comparison does not need one, because both trees are already in the tab.
How is this different from a text diff or a CSV diff?
A json compare and a line diff are different jobs. JSON diff versus text diff is a difference of subject. A text diff answers "which lines changed in this source file?" This page answers "which values changed in this JSON?" Use the text diff when spacing in a committed file is the thing you review. Use this page when an API body, a config document, or a log payload is the thing you review.
JSON diff versus CSV diff is the same idea on a different shape. CSV Diff matches rows, often by a key column, and reports cell edits. JSON has no header row. It has paths. Comparing two API responses before and after a deploy belongs here. Comparing two spreadsheet exports belongs on the CSV page. Neither page converts the other format. A table pasted as JSON stays JSON. A JSON array of objects is still a structural diff, not a row diff, even when it looks tabular.
YAML, JSON Schema, and a three-way merge are out of scope. Convert YAML to JSON first if you need this compare. A schema says whether a document is allowed. It does not say how two documents differ. A merge tries to produce a third document. This page only lists paths.
Related Tools
You May Also Need
You may also need
- CSV DiffCompare tabular exports the same way, by row instead of by path
- JSON FormatterPretty-print one side after the values are the ones you wanted
- JSON ValidatorSee a single document syntax error before you compare two
Next steps
- JSON ValidatorValidate the side that failed to parse before you try the diff again
- JSON FormatterFormat the reconciled document once the paths match
Alternatives
- JSON FormatterChoose this when the job is indentation, not a comparison
- CSV DiffChoose this when the files are CSV rows rather than JSON values