ToolsTray

Star a tool to keep it here.

JSON Diff — Structural Compare

A JSON diff that parses both sides before it compares them, so reordered keys count for nothing and every real change arrives as a key path like items[2].price.

Drag & drop your file here, or

Drag & drop your file here, or

Comparison rules

    How to use

    1. Put the version you are treating as the baseline in Original JSON and the one you want to check in Revised JSON. Dropping a .json or .txt file on either box loads it into that side.
    2. Press Compare. It also recompares on its own while you type, so tweaking either side updates the result without going back to the button.
    3. The three view buttons decide what you are looking at. Split puts the documents next to each other with the differences highlighted, Unified stacks them into a single column, Changes hides both and leaves only the list of paths. A narrow screen opens on Unified.
    4. Download .diff saves the patch as json-changes.diff, and the copy button beside it puts the same text on your clipboard for a ticket or a PR comment.

    How the comparison works

    Two API responses can hold identical data and still look completely different to a line diff. Keys come back in a new order. One side is minified and the other was pretty-printed at four spaces. The whole screen lights up red and none of it means anything, because objects in JSON have no defined key order and a text comparison is answering a question nobody asked. Parsing both sides first is the only way a JSON diff can tell you anything useful, and that is what happens here. What comes back is a list of the key paths where the data genuinely differs, with the values printed underneath each path.

    Paths read the way you would write them in code. A nested key shows as user.profile.city, an array element as items[2].price, and the top level of the document as (root). Every entry lands in one of three buckets: added, removed, changed. A value that switched type counts as changed, so an id that used to be the number 7 and now arrives as the string "7" gets caught instead of passing for equal. Objects recurse as deep as they go, and arrays line up position by position unless you tell it otherwise.

    Two versions of one account record

    Put {"id":7,"plan":"pro","seats":3} in the left box and {"seats":"3","id":7,"plan":"pro","region":"eu"} in the right one. The summary line reads +1 added · −0 removed · 1 changed.

    Every key those two payloads share sits in a different position, and none of that gets reported, which is the whole point. What you get is region added with the value "eu", and seats changed from 3 to "3". A number that quietly became a string is the sort of thing that ships on a Friday and breaks a client the following week.

    Good to know

    • Arrays match up by position. Insert one element at the front of a 200-item list and every index behind it reads as changed, which is technically true and practically useless. Ignore array order is the escape hatch when sequence was never meaningful.
    • The change list sorts by the path as text, so rows[10] sits above rows[2] rather than below it. Sorting that way keeps the output stable between runs; it makes no attempt to be numeric.
    • Nothing is compared until both sides parse. One stray trailing comma gets you a red line naming which box broke and where, and no diff at all until you fix it.

    Frequently asked questions

    Do reordered keys show up as differences?

    They do not. Objects in JSON carry no order, so {"a":1,"b":2} and {"b":2,"a":1} come out equal and the change list stays empty. Whitespace is invisible to it as well: minified on one side and four-space indented on the other still compares as the same document.

    Two responses list the same records in a different sequence. Can I compare them?

    Tick Ignore array order. Every array on both sides is sorted by its own content before anything is compared, so ten records that came back shuffled read as equal. Objects inside those arrays are matched on content too, whatever order their keys are in. The toggle feeds the highlighted views and the exported patch as well, so the verdict and the highlighting never disagree with each other.

    What is actually inside the exported patch?

    A standard unified diff between two files named original.json and revised.json, with three lines of context around each hunk. Both sides are rewritten first with their keys sorted alphabetically and two-space indentation, so the patch carries the structural change and not whatever formatting your editor happened to apply.

    Can it merge the two documents for me?

    It stops at telling you what moved. Applying the changes stays with your editor or your version control, which is where you want that decision made anyway. Take the patch if you need something to hand to a reviewer.

    Why is half my array marked changed when I only added one row?

    Because elements are matched by position. Put a new row at the front of [1,2,3] and you get three changed entries plus one added, since every value slid one place along. If sequence carries no meaning in that array, Ignore array order clears the noise; if it does carry meaning, read the added entry rather than the changed ones, because that is the element which actually turned up.

    How do I catch a number that turned into a string?

    A type switch is reported as a changed entry with both sides printed, so 3 → "3" appears in full and the quotes are the tell. Between two versions of the same endpoint that is the most common thing this catches. Worth checking every time a backend gets rewritten in another language, because it is exactly where the id types drift.

    Can I compare two .json files instead of pasting?

    Drop one on each box at the top. Either side takes a .json or a .txt file, the text lands in the box, and you can still edit it before comparing. There is no size cap written into the tool; both documents are parsed and held in the tab, so a few megabytes a side is comfortable and a hundred is asking for trouble.

    Missing something in JSON Diff — Structural Compare? Suggest a feature →

    Tell someone who needs this.