diffthesetwo.com Runs in your browser
Two JSON documents → difference

Compare two JSON documents

A structural diff: added, removed, and changed values by path, with key order and formatting ignored entirely.

JSON comparison


Paste JSON into both boxes to compare them.
Added
Removed
Changed

Why a text diff lies about JSON

JSON makes promises about data and none about characters. The specification says object members are unordered, so a serialiser is free to emit keys in any order it likes — and they do, differently between libraries, library versions, and sometimes between two runs of the same program. Add pretty-printing against minification, two-space against four-space indentation, and a trailing newline or not, and two byte-for-byte different files can encode exactly the same document. Run those through a line diff and you get pages of changes with the one real difference buried somewhere inside them.

The fix is to stop comparing text. This tool parses both documents and compares the values the parser produced, which is what every program consuming the JSON actually sees. Key order cannot register as a difference because the parsed objects have no order to compare; whitespace cannot register because it never survives parsing. Numbers are compared as values, so 1.0 equals 1 and 1e3 equals 1000 — with the standard caveat that both sides pass through IEEE doubles, so integers beyond 253 compare by their rounded value.

Reading the report

Every difference is reported at a path — the route from the top of the document to the value that differs, written in dot-and-bracket notation like user.roles[2]. There are three kinds of entry:

  • + added — the path exists only in the changed document. The value shown is everything under it.
  • − removed — the path exists only in the original.
  • ~ changed — the path exists in both with different values, shown as before → after. A value changing type, say the string "8080" becoming the number 8080, is one change at that path, not a subtree of adds and removes.

The guarantee runs both ways: every reported entry is a real difference in the parsed data, and no formatting or key-order difference ever appears.

null is not a missing key

A key set to null and a key that is not there at all are different documents, and most APIs treat them as different instructions. JSON Merge Patch (RFC 7386) is the clearest example: sending {"email": null} deletes the email field, while omitting the key leaves it alone. This diff keeps the three cases distinct — null to absent is a removal, absent to null is an addition, and a value becoming null is a change — because collapsing them hides exactly the bugs a JSON diff exists to catch.

The array limitation, honestly

Arrays are ordered, so they are compared index by index. That is correct — [1, 2] and [2, 1] are genuinely different documents — but it is blunt about moves. Insert an element at the front of a ten-element array and every index after it reports as changed, plus one addition at the end, because the tool cannot know that element three is "the same object" as element two without an identity key to match on, and guessing would produce confident nonsense. For a reordered array of scalars, the line-by-line text differ on the homepage can be the better instrument: paste one element per line and its longest-common-subsequence matching will show the move as a single line shifted rather than a cascade of changes.

Common questions

Why does a normal diff tool show differences when the JSON is the same?

Because a text diff compares characters, and JSON gives no guarantee about characters. The same object can serialise with its keys in a different order, different indentation, or no whitespace at all depending on the library and version that produced it. A structural diff parses both documents first and compares the values, so two renderings of the same data always compare as identical.

How are arrays compared?

Index by index: the first element against the first, the second against the second, and any leftover elements on the longer side reported as added or removed. That means an element moving to a new position shows up as changes at both positions rather than as a move — the tool has no way to know that two elements are “the same one” without an identity key, and it does not pretend to.

What is the difference between null and a missing key?

They are different values in JSON and different instructions to most APIs. In JSON Merge Patch (RFC 7386), sending a key with null deletes that field, while omitting the key leaves it untouched. This diff keeps the two apart: a key going from null to absent is a removal, absent to null is an addition, and a value becoming null is a change.

What does a path like user.roles[2] mean?

It is the route from the top of the document to the value that differs: the roles key inside the user object, third element (indexes count from zero). Keys that are not plain identifiers are bracket-quoted, so a literal key named “a.b” prints as ["a.b"] and can never be confused with a nested lookup of a then b.

Why is one of my documents reported as invalid?

The usual culprits are a trailing comma after the last item, single quotes instead of double quotes, unquoted keys, or a comment — all legal in JavaScript and illegal in JSON. The error under the box reports the exact line and column the parser stopped at, though the real mistake is often just before that point, such as a missing comma on the previous line.

Is my JSON uploaded?

No. Both documents are parsed and compared entirely in your browser and nothing is sent to a server, logged, or stored. That matters more for JSON than for most text, because pasted JSON so often contains API keys, tokens, and personal data.