What JSON Diff does
This tool parses both documents and compares the data, not the text. Two objects with the same keys in a different order are equal, and so are a minified file and a pretty-printed copy of it. What you get back is a table with one row per difference: the path (for example scripts.dev or tags[1]), whether it was added, removed or changed, and the original and changed values. Counts for each kind sit above the table, with the number of values that are the same on both sides. Arrays are compared position by position, because order in a JSON array carries meaning. If either side fails to parse, the error says which box it is and where the problem is.
Worked examples: what each kind of change looks like
Each result below is the real output of the tool for the input shown.
Same data, different key order
Original: {"a":1,"b":{"c":2,"d":3}} Changed: {"b":{"d":3,"c":2},"a":1.0}
No differences. 3 unchanged values.
The keys are reordered at two levels and 1 is written as 1.0. None of that changes the data.
A value changed and a key added inside a nested object
Original: {"scripts":{"dev":"next dev","build":"next build"}} Changed: {"scripts":{"build":"next build","dev":"next dev --turbo","lint":"eslint ."}}
Changed scripts.dev: "next dev" to "next dev --turbo". Added scripts.lint: "eslint .". 1 unchanged value.
A type change
Original: {"id":1,"v":null,"o":{}} Changed: {"id":"1","v":0,"o":[]}
3 changed: id (number to string), v (null to number), o (object to array).
An item inserted at the start of an array
Original: ["a","b","c"] Changed: ["x","a","b","c"]
Changed [0], [1] and [2]; Added [3]: "c". 4 differences.
Arrays are matched by position, so an insertion shifts every later item. See the section on arrays below.
Nested arrays of objects, JSON Pointer paths
Original: {"users":[{"id":1,"roles":["a","b"]},{"id":2}]} Changed: {"users":[{"id":1,"roles":["a"]},{"id":3,"x":true}]}
Removed /users/0/roles/1: "b". Changed /users/1/id: 2 to 3. Added /users/1/x: true.
What counts as a difference and what is ignored
| Situation | Reported as | Why |
|---|---|---|
| Keys in a different order | No difference | JSON objects are unordered |
| Different indentation, line breaks or minification | No difference | Whitespace between tokens is not data |
| 1 and 1.0, or 1e2 and 100 | No difference | Both parse to the same number |
| "caf\u00e9" and "café" | No difference | An escape and the character it stands for are the same string |
| Key present only in Changed JSON | Added | The path is new |
| Key present only in Original JSON | Removed | The path is gone |
| Same path, different value | Changed | Both values are shown |
| Same path, different type (1 and "1", {} and []) | Changed, with both types named | Types are compared before values |
| null on one side, key missing on the other | Added or Removed | A null value is still a present key |
| Array items in a different order | Changed at each position that differs | Array order is significant in JSON |
| A trailing space inside a string | Changed | Strings are compared exactly |
How arrays are compared, and when that is not what you want
Item 0 of the original is compared with item 0 of the changed document, item 1 with item 1, and so on. If one array is longer, the extra positions are listed as Added or Removed. This is exact and predictable, and it matches how most code reads an array.
The cost shows up when an item is inserted or deleted near the start. Every later item moves by one position and is reported as Changed, even though it only shifted. The tool does not try to detect moves or match array items by an id field. [1,2,3] against [3,2,1] gives two differences, at [0] and [2].
If the order of a list does not matter in your data, such as a set of tags or permissions, sort the array the same way on both sides before pasting and the comparison becomes order-independent for that list.
Dot notation and JSON Pointer paths compared
The Path style option changes only how each location is written. JSON Pointer is the format from RFC 6901, used by JSON Patch and JSON Schema.
| Location | Dot notation | JSON Pointer |
|---|---|---|
| Key dev inside scripts | scripts.dev | /scripts/dev |
| Second item of tags | tags[1] | /tags/1 |
| Key x of the second user | users[1].x | /users/1/x |
| A key that contains a dot: a.b | ["a.b"] | /a.b |
| A key that contains a slash: k/z inside "x y" | ["x y"]["k/z"] | /x y/k~1z |
| A key that contains a tilde: ~t | ["~t"] | /~0t |
| The whole document | (root) | (root) |
In JSON Pointer a slash inside a key is written ~1 and a tilde is written ~0.
Limits to know before you rely on the result
- Numbers are held as JavaScript doubles. Integers above 9,007,199,254,740,991 and decimals with more than 17 significant digits are rounded before comparison, so 12345678901234567890 and 12345678901234567891 compare as equal. The tool shows a warning when it sees such a number; quote those values as strings to compare them exactly.
- If a key appears twice in the same object, the last one wins, as in every standard JSON parser. The earlier value is not compared.
- Input must be strict JSON. Comments, trailing commas, single quotes and unquoted keys are reported as errors, as are JSON5 and JSONC files.
- The table shows the first 500 differences. The text summary under it always lists all of them.
- Values longer than 160 characters are shortened in the table. A changed object or array is shown whole only when its type changed; otherwise the rows point to the individual paths inside it.
- The page does not put your input into the address bar, so a comparison cannot be shared as a link. Copy the text summary instead.
Using JSON Diff
- 1
Paste the earlier version into Original JSON.
- 2
Paste the later version into Changed JSON. The result updates as you type.
- 3
Choose a Path style: dot notation such as user.roles[0], or JSON Pointer such as /user/roles/0.
- 4
Read the Summary for the counts, then the Differences by path table for each path with its original and changed value.
- 5
Copy or download the Text summary if you want to paste the list into a pull request or a ticket.