Skip to the tool
DevToolBench

JSON Diff

Compare two JSON documents by value, with a JSON Patch out.

Original
Changed

Key order is always ignored, because an object is a set of pairs and two orderings of the same pairs are the same document.

Added
0
Removed
0
Changed
0
Total
0

Everything runs in your browser. Nothing you type is sent to a server.

Found a bug in this tool? Report it.

Share this tool

A JSON diff that reads the structure, not the characters

This JSON diff parses both documents and compares the values, so what you get back is a list of paths — orders[2].status, limits["rate/min"] — with the old value and the new one, plus the same change expressed as a JSON Patch you can paste into a request. Reformatting, reordered keys and a number written two ways stop being findings, because none of them changes what a consumer reads.

Paste an original on the left and a changed version on the right. Nothing is compared until both sides parse; if one of them does not, you get the line and column where it gave up rather than a generic complaint.

Why comparing JSON as text misleads you

Every JSON serialiser makes choices that the format does not fix. Key order is one: JSON.stringify preserves insertion order, Python's json.dumps can sort, Go's encoding/json sorts map keys always, and a database export may follow the column order. Indentation is another, along with whether non-ASCII characters are escaped and whether a float keeps its trailing zero.

Run a line-based diff across two files that disagree on all four and you get a wall of red and green describing nothing. Worse is the opposite failure: a genuine change buried inside three hundred cosmetic lines, which is how a modified timeout or a flipped boolean gets approved in review.

The structural comparison here fixes the rules in advance. Key order never counts. Array order counts by default, because position is meaningful in a sequence. Numbers compare by value unless you turn that off, in which case 1 and 1.0 become a reported difference — useful when you are chasing a serialiser that changed, and noise when you are not.

What a change looks like

Three kinds of finding, and no others. Added means the path exists on the right and not on the left. Removed is the reverse. Changed covers a different value at the same path, including a value that changed type — "3" where there used to be 3 is a single change, not a removal plus an addition, because that is the bug you are usually looking at.

A missing key and a key set to null are never conflated. Removing owner and setting "owner": null are different messages to whatever consumes the document: one says the field is gone, the other says it exists and is empty. Tools that collapse the two hide schema migrations.

Paths use the notation you would type in code, so you can copy one straight into a console. Keys that are not valid identifiers are bracketed and quoted instead, which keeps data["first name"] unambiguous.

The patch, and where it goes

The same result comes out as an RFC 6902 patch: an array of add, remove and replace operations, each addressing a location with an RFC 6901 pointer. That is the body of an HTTP PATCH with the media type application/json-patch+json, and it is what a partial-update endpoint expects instead of a full replacement.

Two details in the generated patch are deliberate. Removals from an array are emitted from the highest index downwards, because applying them in the other order shifts every index still to come — remove /items/1 first and the old /items/2 is now /items/1. And an addition to an array whose order you told the tool to ignore uses the append pointer /- rather than a position, since with order declared irrelevant any position would be invented information.

Where it stops being useful

An array of objects with no identity field is the honest limit. Comparing by index means one inserted element at the front reports every subsequent element as changed, and no amount of cleverness fixes that without knowing which field identifies a row. Sort both sides by their key before comparing, or compare the subtrees you care about one at a time.

Very large documents are the other limit. Past five hundred differences the list stops, on the theory that a diff nobody can read is not a result. When two files disagree that thoroughly, they are usually not versions of each other, and the useful question is about a smaller subtree.

Where this fits

If one of the two sides will not parse, the JSON formatter is the faster way to find out why, since it validates and indents in the same pass. When you need to prove a change to someone reading a pull request, the text diff still has its place — it shows the file as they will see it. And when the two documents come from different systems that speak different formats, the JSON to YAML converter puts both into the same shape before you start comparing them.

Everything above happens inside your browser tab, with no upload and no round trip.

Frequently asked questions

Why does a text diff show changes when the two JSON files are the same?

Because a text diff compares bytes and JSON is not defined in bytes. Reserialise the same object with a different library and the key order changes, the indentation changes, a number may come back as 1.0 instead of 1 and a non-ASCII character may arrive escaped as \u00e9 instead of é. None of that alters a single value, and all of it lights up a line-based diff. A structural comparison parses both sides first, so it can only report differences that a consumer of the data would actually see.

What is JSON Patch, and where would I use it?

JSON Patch is RFC 6902, a small format that describes a change to a JSON document as an array of operations — add, remove, replace, move, copy and test — each addressing a location with a JSON Pointer such as /orders/2/status. It is the payload of an HTTP PATCH request with the media type application/json-patch+json, and it is what lets a client send four bytes of intent instead of the whole resource. It also travels well in an audit log, because the operations are the change rather than a picture of the result.

Should the order of a JSON array count as a difference?

Usually yes, and that is the default here. An array is an ordered sequence, so a reordered array is a different document, and pipelines that read the first element or paginate by position genuinely break when the order moves. The exception is the array people use as a set — tags, roles, feature flags, permitted origins — where nothing depends on position. The option to ignore order applies only to arrays whose items are all primitives, for the reason in the next answer.

Why does ignoring order not work for arrays of objects?

Because pairing two objects requires knowing which one is which, and a bare array carries no identity. Given [{"id":1},{"id":2}] against [{"id":2},{"id":1}] a tool can guess that id is the key, but the guess is wrong the moment your identity field is called uuid, sku or _key, and a wrong pairing produces a diff that is confidently misleading. This tool falls back to index-by-index comparison there, which is honest rather than clever. If you control the data, sorting both sides by their key before comparing gives you a real answer.

Does the tool upload my JSON anywhere?

No. Parsing, comparison and patch generation all happen in the page, and there is no request to send them in. That matters more here than in most tools, because the documents people compare are API responses and configuration files, which is exactly the category of text that tends to contain tokens, internal hostnames and customer records.

Related tools

Updated