Free online JSON comparison
Compare JSON by key, not by line
This JSON comparison is free and needs no signup: it parses both documents and matches them by key path, so two payloads whose properties are written in a different order come back as equal instead of wholly different. Arrays can be lined up by position or by an identity key such as id, which turns a re-sorted list into “one item moved” rather than a hundred changes. Numbers are compared as exact decimals — 1.0 equals 1, while a 19-digit order ID never gets rounded into agreeing with its neighbour — and each side takes up to 5 MB.
- 100% free
- No signup
- Key order ignored
- Arrays matched by id
- 5 MB documents
Paste a document into each box. Key order is ignored from the start — only the values behind the keys are compared.
How to compare two JSON documents
Paste both, pick how arrays should line up, read the verdict.
Drop a document into each box
Paste one JSON document into each box, or hit ⌘V on a Mac (Ctrl+V elsewhere) while the page has focus and it fills whichever box is still empty. Each box holds 5 MB and 500 levels of nesting; when a document will not parse, a red bar under it gives the line, the column and what went wrong in plain words, and the comparison waits until both sides are valid.
Decide how array items should be paired
By position is the default and is right for ordered data such as a list of coordinates or a sequence of events. Switch to “by identity key” when the array is a collection — orders, users, routes — and give the key that names each item; the page suggests one from id, _id, uuid, key, sku, code, slug, name or email if it finds a candidate. Matching on an identity key means an item that simply moved is reported as moved, not as one deletion and one addition.
Read the verdict, then the three lists
The bar above the results answers the actual question first — “structurally equal” or a count of differences — and then tells you what it declined to count: how many objects have their keys in a different order, how many numbers are written differently but equal in value, how many strings use different escapes. Below it, differences are grouped into what is only in the first document, only in the second, and present in both with a different value.
Technical specifications
| How things are matched | Objects by key with order ignored; arrays by position, or by an identity key you name — suggested from id, _id, uuid, key, sku, code, slug, name or email when one fits every item |
|---|---|
| When two numbers are equal | After the exponent is applied and trailing zeros dropped, as exact decimal text: 1, 1.0, 1e0 and 0.1e1 agree, while 9007199254740993 and 9007199254740992 stay different |
| When two strings are equal | By decoded characters, so \u00e9 matches é and a\/b matches a/b; the number of strings that only matched after unescaping is reported |
| Reported but not counted as differences | Objects whose keys are in a different order, numbers written differently but equal in value, strings that differ only in their escapes, and every path that carries a duplicate key |
| Duplicate keys | Kept by the parser rather than collapsed; the second occurrence is the one compared, matching the value a normal parser would hand your code, and the path is listed as a warning |
| Size, depth and speed | 5 MB a side, 500 levels. A 5.33 MB pair of 24,000 records — 456,001 nodes, 336,000 keys — compares in 137 ms by position and 180 ms by identity key |
| Listing limits | 400 entries per group on screen; Copy report puts every difference on the clipboard, however many there are |
| Price and where it happens | Free, nothing to register for, no quota on how many pairs you check; parsing and comparison both take place inside this browser tab |
Frequently asked questions
Why do reordered JSON keys show up as changes in other tools?
Because those tools are comparing the text, not the data. In JSON the sequence an object's members are written in carries no meaning, so {"a":1,"b":2} and {"b":2,"a":1} hold identical information — but as strings of characters they are plainly different, and a line-based comparison has no way to know the difference does not matter. Serialisers reorder constantly: Go's encoding/json sorts map keys alphabetically, Python's json.dumps preserves insertion order, JavaScript promotes every key that could pass for an array index ahead of the rest. This page pairs members by name from the start, so all of that disappears, and how many objects were reordered is reported as information rather than as a difference.
How do I compare two arrays whose items are in a different order?
Switch array matching to “by identity key” and name the field that identifies an item. Position matching is the honest default because JSON arrays genuinely are ordered — [1,2] and [2,1] are different documents, and pretending otherwise would be wrong. But a list of orders keyed by id is a collection that happens to be stored in an array, and comparing it by position turns a re-sorted API response into a hundred false differences. With an identity key, an item that only moved is reported as moved, an item whose values changed is reported at its new position, and only genuinely new or missing items count as additions and removals.
Are 1.0 and 1 the same value here?
Yes by default, and you can switch that off. Both literals are rewritten as an exact decimal string before they are compared — the exponent is applied by moving the decimal point, then trailing zeros are dropped — so 1, 1.0, 1e0 and 0.1e1 all collapse to the same form. The obvious alternative, comparing Number(a) === Number(b), would agree about those and then get the important case wrong: 9007199254740993 and 9007199254740992 are the same 64-bit float and different integers, and an order ID that differs in its last digit is exactly the difference you cannot afford to miss. Shifting the decimal point by hand keeps every digit.
What happens when a document has the same key twice?
Both occurrences survive the parse, the second one is what gets compared, and the path is listed as a warning. The standard only recommends unique names rather than requiring them and leaves the result undefined when a document ignores that advice, so the useful reading is whichever value your own code will end up with — and in practice every mainstream parser resolves a repeated name to the value written last. Comparing anything else would answer a question nobody asked. The warning earns its place because a repeat is invisible the moment a document has been through a parser, and it nearly always means the template or the merge step that produced the file is emitting a field twice.
Does "é" written as \u00e9 count as a difference?
No. Strings are compared by the characters they decode to, not by the escapes used to write them, so "caf\u00e9" and "café" are equal — as are "a\/b" and "a/b", since the forward-slash escape is optional in JSON. Serialisers differ here for no reason that concerns you: Python's json.dumps escapes non-ASCII by default, JavaScript's JSON.stringify does not, and PHP does unless you pass JSON_UNESCAPED_UNICODE. The count of strings that matched only after unescaping is shown in the status bar, because occasionally that is the thing you were looking for.
How large and how deeply nested a document can it handle?
5 MB a side and 500 levels of nesting. A realistic 5.33 MB pair — 24,000 records, 456,001 nodes, 336,000 keys — parses in about a tenth of a second per document and compares in 137 ms when arrays are matched by position, or 180 ms by identity key. The deliberately awkward case, two 5.33 MB documents where every object has its keys in the opposite order, returns “structurally equal” in 143 ms and reports 24,000 reordered objects.
Do the documents get uploaded?
No. Both are parsed and compared by JavaScript inside this tab, so a database export or a customer payload can be checked here without any of it leaving the machine.
About comparing JSON structurally
One word in RFC 8259 §4 decides how JSON ought to be compared, and the word is unordered. The sequence an object’s members happen to be written in is not part of the data, so any comparison that treats that sequence as meaningful will be wrong — and treating it as meaningful is the only thing a text comparison can do, because text has no other option. This matters more than it sounds, because machinery downstream of JSON quietly disagrees with the standard: a detached signature, an ETag, a content hash or a cache key computed over the serialised bytes all change when the key order does, even though the document means the same thing. The rule of thumb worth keeping is that JSON equality is a question about the parse tree and everything else is a question about the bytes, so decide which one you are actually asking before you pick a tool.
Arrays are where structural comparison stops being obvious. An array is ordered — RFC 8259 defines it as an ordered sequence, and [1,2] genuinely is not [2,1] — so a tool that silently ignores array order would be lying about your data in the other direction. The trouble is that most arrays in practice are collections, not sequences: a list of users, of line items, of feature flags, whose order is whatever the database returned. Comparing those by position turns one re-sorted response into an avalanche, and there is no way for a program to tell the two cases apart without being told. That is what the identity key is for: naming the field that makes an item itself is the one piece of knowledge the comparison cannot infer, and once it has it, moved items are moves and only real arrivals and departures count.
Two smaller decisions are worth knowing about because tools disagree on them. Numbers here are canonicalised as decimal text rather than turned into floating point, so no comparison ever loses a digit — the same reason the JSON viewer shows long identifiers exactly as they were written. Strings are compared by what they decode to, so escape style is invisible. And duplicate keys, which most parsers silently collapse, are kept and reported: if a template is emitting a field twice, this is usually where you find out. Once you know what differs and want a machine-readable description of how to fix it, the JSON diff page runs the same comparison and emits an RFC 6902 patch instead of a report; if the document will not parse at all, the JSON checker points at the character responsible.
Where the two payloads are compared
Both documents are parsed and compared inside this browser tab. Nothing is uploaded, cached or logged, which is why a payload containing customer records can be checked here — and why the comparison keeps working with the network disconnected.