Skip to content

JSON diff

Compare two JSON documents by their DATA, not their text — so reformatting and reordered keys are not reported as changes.

The one genuinely ambiguous case. Insert an item at the front of a list and a positional comparison reports every single element as changed.
Runs in your browser — nothing is sent anywhere.

Why a text diff fails on JSON

JSON has no canonical text form. The same data can be minified onto one line, indented with two spaces or four, and have its keys in any order — and all of those are the same document.

A line-based diff does not know that. Reformat a file and it reports every line as changed. Reorder two keys and it reports both as changed. Meanwhile a genuine difference buried inside a minified API response shows up as "line 1 changed", which tells you nothing at all.

This compares the parsed values instead. Whitespace is irrelevant, key order is irrelevant, and the answer is a list of paths: what was at each one before, and what is there now. That is the question anyone comparing two API responses or two config files is actually asking.

It will tell you explicitly when two documents have identical data but different text, which is a result a text diff can never give you and is often exactly what you needed to know.

Lists are the genuinely hard part

Everything else about a structural diff is mechanical. Arrays are ambiguous, and the ambiguity is not resolvable without knowing what the list means — so it is a choice rather than a default.

By position compares item 1 with item 1. It is what a naive diff does, and it falls apart on the most ordinary edit there is: insert one item at the front of a list and every single element after it is reported as changed. On a five-item list that is five differences where there was one.

Matched by id looks for a field that identifies each item — id, uuid, sku, email and a few others — and pairs items up by it. That same front insertion is then reported as what it is: one addition. This is nearly always what you want for API data, and it is the default.

The matching field has to be unique within each list, not across both of them. Checking the two lists together is the obvious way to write it and it is wrong — an item present in both contributes its id twice, so the check fails on exactly the documents where matching would have helped, and quietly falls back to comparing by position.

As a set ignores order completely. Right for a list of tags, permissions or feature flags, where the order was never meaningful and a reordering is not a change. Duplicates are still counted, so a list losing one of its two copies of a value is reported.

Type changes are called out separately

"5" becoming 5 is the kind of difference that breaks things downstream and is invisible in a text diff, because the only textual change is two disappearing quotes. Likewise a value becoming null, or a single object turning into an array of one. Those are reported as type changes rather than lumped in with ordinary value changes.

A JSON Patch, when one is possible

If you want to apply the difference rather than read it, RFC 6902 is the format APIs expect, and it can be produced here.

With one honest exception: a patch cannot be produced when lists are matched by id. RFC 6902 addresses array items by position, and "the item whose id is c" has no pointer form at all. Rather than emitting something that looks like a patch and applies to the wrong element, that combination is refused with the reason. Compare by position if you need the patch.

Nothing is uploaded

The two things people most often compare are API responses and configuration files. The first routinely contains a session token, the second routinely contains a password. Neither should be pasted into a website that sends it anywhere, so this one does not — the comparison happens in the page.

01

Common questions

Why does a normal diff say everything changed?

Because JSON has no single text form. Reformatting or reordering keys changes every line while changing no data. This compares the parsed values, so neither is reported.

How do I paste two documents?

Both in the one box, separated by a line containing only ---. Two boxes would be tidier and worse: you usually arrive with the two things on the clipboard one after the other.

My list has one new item and it says everything changed.

That is positional comparison. Switch to matching by id — an item inserted at the front is then reported as one addition rather than as a shift of everything after it.

What counts as an id?

A field like id, uuid, _id, key, name, slug, sku, code or email, provided its values are unique within each list. If none qualifies it falls back to comparing by position.

Why can I not get a JSON Patch?

Only when lists are matched by id. RFC 6902 addresses array items by position, so an id-matched location has no pointer form. Compare by position and the patch is available.

Does it notice "5" becoming 5?

Yes, and it reports it as a type change rather than a value change. In a text diff that difference is two vanished quote marks.

Is my data uploaded?

No. The two things people compare most are API responses and config files — one usually has a token in it and the other a password — so the comparison runs in this page.