IT
OmnvertImage • Document • Network

JSON Diff & Compare

Compare two JSON documents side by side. Path-aware adds, removes and value changes — entirely in your browser.
Developer Tools →
Original
190 chars
Modified
240 chars
Added
3
Removed
1
Changed
3
Unchanged
5
Diff
$.name = "Acme Inc."
$.products[1] = "Rocket Skates"
 
$.address.zip = "91501"
 
$.rating = 4.2
 
$.name = "Acme Corp."
$.products[1] = "Mega Rocket Skates"
$.products[3] = "Dynamite"
$.address.zip = "91505"
$.address.country = "USA"
 
$.ceo = "Wile E. Coyote"
100% client-side: both JSON inputs never leave your browser.
About this tool

Diffing JSON sounds like a textual problem until you actually try to do it. Run two JSON documents through a line-based diff tool and the output is almost useless: a single reordered key in an object cascades into a wall of red and green even though no semantic change happened, an added property at the top of an object pushes every following line down by one and lights up the rest of the diff as 'changed', and an array reordered without value changes shows as a complete rewrite. The reason is that line-based diffs treat JSON as text, but JSON is a tree. The right unit of comparison is a path through that tree — a.b[2].c — not a line number. A path-aware diff knows that swapping the order of two keys in an object is a no-op, knows that array index 2 in the left document is the same slot as array index 2 in the right one, and knows that the only thing that changed at user.profile.email is the email itself, not all the surrounding keys that happened to appear on the same line.

This tool implements that path-aware comparison. Paste the original JSON on the left, the updated version on the right, and the diff engine walks both trees in parallel, recursively, recording an operation at every leaf where the values disagree. The four operations are added (a key or array element exists on the right but not on the left), removed (it exists on the left but not on the right), replaced (both sides have a value at this path but the values are different), and same (both sides match — included in the report so you have full context, hidden by default in the side-by-side view to keep the focus on what changed). The output gives you a path, an old value, a new value, and an operation type, formatted for either a unified textual report (paste into a Slack thread or a GitHub comment) or a side-by-side visual comparison (review like a code diff).

Path syntax is worth a sentence. Object keys use dot notation: a.b.c means object a, key b, key c. Array indices use bracket notation with the integer index: items[0], items[3].name. The two compose: orders[0].lineItems[2].sku is exactly what you would write in JavaScript to reach that field, which is the entire point — a path-aware diff produces paths you can paste straight into your code, a console expression, or a JSONPath query. Keys that contain dots, spaces, or other awkward characters are quoted: data['weird.key with spaces'].value. The diff engine emits these correctly so you can drop them into JSONPath, JMESPath, or jq with minor adjustments and they keep working.

Where this tool earns its keep is review and audit work. Reviewing an API change where the response shape evolved between versions: paste old and new responses, see exactly which fields appeared, disappeared, or changed type. Auditing a configuration change after a production incident: paste yesterday's config and today's config, get a precise list of every value that moved. Comparing two environments when something works in staging but not in production: paste both feature-flag dumps, see the one flag that diverged. Verifying a migration script: paste a record before and after, confirm every field moved correctly. In all four cases, a textual diff would surface noise; a path-aware diff surfaces signal.

The tool handles the awkward edge cases that trip up naive implementations. Numeric equality is value-based, not string-based, so 1 and 1.0 compare equal, but 1 and "1" do not — the type difference is real and is reported. Null is a distinct value, not a synonym for missing — a key whose value is null on the left and missing on the right shows as a removal. Booleans, numbers and strings each compare with strict equality. Nested objects and arrays compare structurally: two empty objects {} match, two empty arrays [] match, but {} and [] do not — they are different types even though both are technically 'empty'. Date strings, ISO timestamps, UUIDs, and other domain-specific formats are compared as opaque strings, which is the right default; if you need fuzzy or semantic comparison, the tool gives you the raw differences and you script the fuzziness on top.

Side-by-side view mirrors the experience of reviewing a code diff. The left panel shows the original document with removed lines highlighted in red, the right panel shows the updated document with added lines highlighted in green, and lines that changed in place show the old value on the left and the new value on the right at the same vertical position. Modified lines have a subtle orange/amber highlight rather than the red+green split that line-based diff tools use, which makes it instantly clear at a glance whether a change was a true add/remove or just a value update. Line numbers are preserved on both sides for cross-reference. Unchanged lines are visible by default but can be hidden with the 'show unchanged' toggle when the diff is large and you want to focus only on the changes.

Unified view is the textual report. Each change is one line in the form `[OP] path = value` or `[~] path: oldValue → newValue` for replacements. The format is designed to be copy-paste safe — Markdown-renders cleanly in GitHub comments, fits in Slack threads, and stays readable when wrapped to 80 columns. The four stat tiles at the top of the page (added, removed, changed, unchanged) give you the count of each operation, useful for at-a-glance triage of how invasive a change is. A diff with 2 changes is review-worthy; a diff with 200 changes is a structural rewrite that probably needs a different conversation than a line-by-line review.

Performance matters because JSON documents in real engineering work are not always small. The diff engine handles documents up to several megabytes without lag, runs the comparison synchronously on the main thread for documents up to ~1MB and on a Web Worker for larger inputs, and renders the side-by-side view virtualized so a diff with 10,000 lines does not blow up the browser. For genuinely huge documents (hundreds of megabytes), command-line tools like jd or diff-json are faster and you should use those, but for the common case of comparing two API responses, two configs, or two records — the kind of diffing that happens dozens of times a day on an active project — the browser implementation is fast enough to feel instantaneous.

Privacy is built into the architecture, not bolted on. The diff runs entirely in your browser using local JavaScript; no JSON is uploaded, no diff result is logged, no telemetry is captured beyond a generic page-view ping that does not include the contents of either text area. This matters when the JSON you are comparing contains real production data — customer records, internal system state, API tokens, anything you would not want to paste into a third-party service. You can verify the privacy claim by opening your browser's network tab and watching the Network panel during a diff: there are no outbound requests except for the static page assets that loaded the tool itself.

A few patterns we see often. First, normalize before diffing — if you control the JSON output, sort object keys alphabetically and write a stable serializer; this makes textual diffs (when you do need them) actually useful, and it makes your path-aware diffs more deterministic. Second, store key API responses as test fixtures, and diff incoming production responses against them as a contract test; a CI job that fails when the diff is non-empty is a tight feedback loop for spotting accidental schema changes. Third, when reporting a JSON-related bug, include the diff between expected and actual, not just the actual; this tool produces a copy-pastable diff in the unified format that is exactly what a reviewer needs. Fourth, for very large diffs, focus on the stat tiles first — knowing whether the diff is 90% additions vs 90% modifications tells you immediately what kind of change you are looking at.

This tool pairs naturally with the rest of Omnvert's developer utilities. After diffing, you might paste the larger of the two documents into the JSON Viewer to navigate it interactively, or use the JSON to TypeScript tool to generate a type definition from one of the documents and then run the other through the same generator to compare the resulting interfaces — a structural diff at the type level is a useful complement to a value-level diff. The Schema.org JSON-LD Builder often produces JSON that you want to verify against an older version, and the Regex Tester is handy for surgical search-and-replace if a diff reveals that the only difference is a token that needs to be substituted globally.

One last thing: a path-aware diff is not a JSON Patch. JSON Patch (RFC 6902) is a related concept — an ordered list of operations that, when applied in sequence, transforms one JSON document into another. The output of this tool is not a valid JSON Patch by default, although it could be converted into one with a small script. The reason for the difference is intent: JSON Patch is designed to be applied (the operations execute against a target document), while this tool is designed to be read (the operations describe what changed for a human reviewer). Both views of 'difference' are useful; this tool focuses on the readable view, with hooks (paths and operation types) that make it easy to script the applicable view if you need it.

Use cases
  • Compare two API responses to spot schema drift between versions.
  • Audit a config change after an incident — see exactly which keys moved.
  • Compare staging vs production feature-flag dumps to find environment skew.
  • Verify a database migration by diffing a record before and after.
  • Review structured-data (JSON-LD) edits across two page revisions.
  • Check that a generated payload matches an expected fixture, character-perfectly.
  • Triage a 'something changed' bug by diffing yesterday's response against today's.
  • Teach the difference between a textual diff and a structural diff with concrete examples.
How it works
  1. 1Paste the original JSON into the left panel and the updated JSON into the right panel.
  2. 2Pick a view: side-by-side for visual review or unified for a textual report.
  3. 3Toggle 'show unchanged' if you want surrounding context, otherwise keep focus on changes.
  4. 4Read the 4 stat tiles for the change shape (added / removed / changed / unchanged counts).
  5. 5Click any path in the diff to copy it for pasting into a console expression or bug report.
  6. 6Use Copy report to export the unified diff, or Download .txt for an offline record.
FAQ
Why not just use a regular diff tool?
Line-based diff tools treat JSON as text. Reorder a key, add a property at the top, or shift an array — the line numbers all change and the diff lights up red/green even when nothing semantically moved. A path-aware diff walks the tree and reports only true differences, with a path you can paste into your code or a JSONPath query.
Are 1 and 1.0 treated as equal?
Yes. Numbers are compared by value, so 1 and 1.0 match. But 1 and "1" do not — the number/string type difference is real and is reported. Null and missing are also distinct: a key with the value null is different from a missing key.
Can I diff arrays where the order does not matter?
By default the diff is order-sensitive: items[0] in the left is compared to items[0] in the right. For unordered arrays (sets), the cleanest workflow is to sort both sides by a stable key before pasting them in. We may add an unordered-mode toggle in a future version.
How does the path syntax work?
Object keys use dot notation (a.b.c) and array indices use bracket notation with the integer index (items[0].name). Keys that contain dots, spaces, or other awkward characters are quoted: data['weird.key'].value. The format is compatible with JSONPath and works in jq with minor adjustments.
How big a JSON document can I diff?
Several megabytes per side is comfortable. The engine runs synchronously up to ~1MB and on a Web Worker for larger inputs. For genuinely huge documents (hundreds of megabytes) command-line tools are faster, but everyday API responses and config files are well within range.
Is anything I paste sent to a server?
No. The diff runs entirely in your browser; nothing is uploaded, nothing is logged, nothing leaves your device. You can verify by opening the network tab during a diff — there are no outbound requests beyond the static page assets.
Can I generate a JSON Patch from the diff?
Not directly — this tool produces a human-readable diff, not a machine-applicable JSON Patch (RFC 6902). The output gives you paths and operation types, which makes it easy to script the conversion if you need it, but the default report is designed for review.
Why are some changes shown as both 'added' and 'removed' instead of 'changed'?
When the type of a value changes (string → object, number → array), the engine records a remove of the old value and an add of the new one rather than a single 'changed', because there is no meaningful 'old → new' value pair to display. Same-type value changes are reported as a single 'changed'.