Free JSON Compare

Compare two JSON objects and see the differences highlighted.

No data leaves your device

JSON Comparison: Why a Text Diff Isn't Enough

The intuitive way to compare two JSON files is to compare them as text, line by line, the way diff has done since 1974. The problem is that JSON is structured. Two semantically identical JSON documents can be written in arbitrarily different text. {"name": "Alice", "age": 30} and the same object pretty-printed across three lines with the keys in reversed order are the same data, but a text diff reports every line as different. A semantic JSON diff reports zero differences. The discrepancy comes from three places: whitespace and formatting (JSON ignores whitespace between tokens, so a pretty-printed file and a minified file are the same data); key order (RFC 8259 §4 defines a JSON object as "an unordered collection of zero or more name/value pairs", JavaScript engines have, since ES2015, standardised an iteration order that preserves insertion order for non-integer string keys, but that is an implementation convenience, not a spec requirement); and recursion (JSON values nest, objects contain arrays which contain objects which contain primitives, and a structural diff has to walk both trees in parallel).

Arrays are different. JSON arrays preserve order by specification, [1, 2, 3] is not the same as [3, 2, 1]. A diff tool that ignores array order would lose meaning; a diff tool that treats array order naively will overreport changes when an element is inserted in the middle (everything that follows looks "shifted"). The combined effect is that text diff is the wrong tool for JSON. It is the right tool for source code (where formatting is part of the meaning), but for data interchange the structure is what matters and the textual presentation is incidental.

A Short History of JSON

JSON's biography is shorter than the average programming language and a great deal less dramatic. The acronym originated at State Software, Inc., a small company that Douglas Crockford and Chip Morningstar founded in March 2001 to build what would later be called Ajax web applications. The first JSON message was sent in April 2001, from a computer in Morningstar's Bay-Area garage. Crockford does not claim to have invented JSON, he peeled it off the JavaScript object literal syntax, gave it a name, and put up a website. He acquired json.org in 2002 and posted a railroad-diagram grammar there. For four years JSON propagated by word of mouth and a slow trickle of library implementations. In December 2005, Yahoo! began offering some of its web services in JSON, the moment most historians point to as JSON crossing into the mainstream. Standardisation came in waves: RFC 4627 (July 2006), authored by Crockford himself, with informational rather than standards-track status; ECMA-404 first edition (October 2013); RFC 7159 (March 2014), which put JSON onto the IETF Standards Track and loosened the requirement that the top-level value be an object or array. The current versions are RFC 8259 (December 2017), now Internet Standard STD 90, and ECMA-404 second edition (December 2017). The two are intentionally identical in grammar; the IETF text adds security and interoperability guidance the Ecma text deliberately omits.

Two Algorithmic Families: Line Diff and Structural Diff

Computer science has been thinking about diffing since the 1970s. Douglas McIlroy (the same McIlroy who invented Unix pipes) and James W. Hunt wrote the original Unix diff in the early 1970s; it shipped as part of the 5th Edition of Unix in 1974, with the underlying algorithm documented in Bell Labs Computing Science Technical Report #41 in June 1976. Hunt-McIlroy is built on the longest common subsequence problem, find the longest sequence of lines that appears in order in both inputs, and everything not in that sequence is either a deletion or an insertion. A decade later, Eugene W. Myers published "An O(ND) Difference Algorithm and Its Variations" in Algorithmica Vol 1, Issue 2 (1986), reframing the problem as shortest-path finding over an "edit graph", the basis for a faster Unix diff implementation that ran two to four times faster than its predecessor. Today, git diff defaults to a histogram algorithm in LibXDiff, generally faster than vanilla Myers and producing more readable output, especially around moved blocks. Patience diff (Bram Cohen, 2008) is another LCS refinement that prioritises unique anchor lines. All variations on a theme: line-by-line LCS, treating the input as a flat sequence of opaque tokens. None of them know what JSON is.

The structural diff family takes a different approach: walk both inputs in parallel, comparing primitives with strict equality, computing the union of object keys (present-in-left only is "removed", present-in-right only is "added", present-in-both means recurse), and walking arrays by index. For each position, recurse. If one array is longer, the extra elements are added or removed. Type changes (number vs string, object vs array) become "type changed" entries. This is the algorithm jsondiffpatch implements as its base case, and it is the algorithm this tool implements. Its strength is that the output is meaningful: every reported change has a path inside the document (user.address.city, items[3].price) and clear semantics. Its weakness is the third step (array comparison by index) which produces nonsense whenever an element is inserted near the front of a long array.

The Hardest Problem in JSON Diffing: Arrays

Suppose your "before" JSON contains the array ["alpha", "beta", "gamma", "delta"] and your "after" JSON contains ["alpha", "new", "beta", "gamma", "delta"]. A naive index-based diff reports four changes: index 1 changed from "beta" to "new"; index 2 changed from "gamma" to "beta"; index 3 changed from "delta" to "gamma"; index 4 added "delta". A human looking at this would say there is one change: a single insertion at index 1. This is the same LCS problem the line-diff family solved in the 1970s, applied to arrays of JSON values rather than arrays of text lines. jsondiffpatch does exactly that, computes the LCS of the two arrays and emits insertions and deletions relative to it. For arrays of primitives this works well. For arrays of objects it does not: [{id: 1, name: "Alice"}] versus [{id: 1, name: "Alicia"}] have no common subsequence by reference equality, so naive LCS reports "delete the whole left element, add the whole right element" when the truth is one field of one element changed. jsondiffpatch's solution is the objectHash callback: the caller supplies a function that maps each object to an identity key (typically obj => obj.id), and the diff matches array elements by identity rather than by reference. This is a hard general problem nobody has fully solved. The Absolutool tool, per its own FAQ, compares arrays by index, it does not implement LCS or objectHash. That is a deliberate scope choice for a small free tool: it is excellent at object diffs and weaker on arrays where elements have been inserted or reordered.

JSON Patch (RFC 6902): Diffs as a Transport Format

RFC 6902, "JavaScript Object Notation (JSON) Patch," was published in April 2013. It defines the media type application/json-patch+json and a six-operation patch language: add, remove, replace, move, copy, test. A patch is itself a JSON document, an array of operation objects, each with an op key, a path key (a JSON Pointer to the target location), and a value or from field as appropriate. Operations are applied in order, atomically: if any one fails, the whole patch is rejected. The path syntax comes from RFC 6901, "JSON Pointer," a companion document published the same month, a tiny string syntax of slash-separated reference tokens (/user/address/city means "the value at key city inside address inside user"; /items/3 means "the fourth element of items", zero-indexed). Because / and ~ are special, they get escaped to ~1 and ~0 respectively (in that order, decoded ~1 first to avoid double-decoding bugs). JSON Patch is the right output format for a JSON diff tool that wants to feed the result to another machine. The HTTP PATCH method (RFC 5789) was designed for exactly this kind of partial-update payload. Kubernetes supports RFC 6902 alongside its own strategic-merge-patch format. This tool does not currently emit JSON Patch, that is a future feature direction, not a current one.

JSON Merge Patch (RFC 7396): The Simpler, Lossy Alternative

RFC 7396, "JSON Merge Patch," was published in October 2014 by Paul Hoffman and James Snell. It uses no operations at all, the patch document is simply a partial JSON object that overlays onto the original. Any field present in the patch overwrites the corresponding field in the original; any field set to null in the patch removes that field; any field absent from the patch is left unchanged; arrays are replaced wholesale, never merged. Merge Patch is concise and easy to write by hand. The trade-off is the loss of expressiveness: there is no way to set a field's value to literal null (because null means "delete"); no way to modify a single element of an array (the whole array gets replaced); no way to express a move or copy; no way to distinguish "I didn't touch this field" from "I want to set it to its current value". For most everyday API updates these limitations are acceptable, which is why Merge Patch is the more popular of the two formats. RFC 6902 wins in scenarios where any of the limitations bite. Kubernetes uses both formats deliberately, picking the right one for each context.

How the Visual Diff Renders

There are three common visual conventions for displaying a structural diff. Side-by-side: two columns, original on the left, modified on the right, with corresponding lines aligned (the layout this tool uses for its inputs). Inline unified diff: a single column showing removed lines (typically prefixed with - and coloured red), added lines (+, green), and unchanged context lines (no prefix, plain text), the layout git diff uses by default. Tree view: render the JSON as a collapsible tree, with changed nodes highlighted and unchanged nodes folded away. Colour conventions are remarkably consistent across the ecosystem: green for additions, red for removals, yellow or amber for changed values, neutral grey for unchanged. This tool follows the convention exactly: light green for additions, light red for removals, light yellow for changes. Most users will recognise the colours from GitHub, GitLab, BitBucket, every IDE diff view and dozens of online tools.

Common Uses

Edge Cases Worth Knowing About

Number precision. RFC 8259 says JSON numbers are arbitrary-precision and puts no upper bound on how many digits a number can have. JavaScript, however, parses every number as a 64-bit IEEE 754 double. Above Number.MAX_SAFE_INTEGER (253 − 1 = 9,007,199,254,740,991), integers may silently lose precision when round-tripped through a JavaScript-based diff. The same problem affects floating-point, 0.1 + 0.2 is famously not exactly 0.3 in IEEE 754. Strict JSON also disallows trailing commas and comments; both are syntax errors per RFC 8259. JSON5 (json5.org) is a formal superset allowing comments, trailing commas, single quotes, unquoted keys, hex numbers, leading/trailing decimal points, and Infinity/NaN. JSONC is Microsoft's "JSON with Comments" mode used in VS Code's settings files. This tool uses JSON.parse() and so will reject both, strip comments and trailing commas before pasting.

Date strings. JSON has no native date type. Dates are typically encoded as strings, with the de-facto standard being ISO 8601 (and specifically the RFC 3339 profile most internet APIs use): YYYY-MM-DDTHH:MM:SS[.fff]Z. A diff that compares dates as strings will report 2024-01-01T00:00:00Z and 2024-01-01T00:00:00.000Z as different (even though they represent the same instant) because the strings differ. Duplicate keys. RFC 8259 §4 states "names within an object SHOULD be unique", the SHOULD is normatively weaker than MUST. JavaScript's JSON.parse() accepts duplicate keys and silently keeps the last one; other parsers may keep the first or raise an error. null vs missing. {"a": null} and {} are different JSON values. This tool reports the first as "key a has value null" and the second as "no key a", they are correctly distinguished. JSON Merge Patch's treatment of null as a delete signal is a format-level admission that the distinction is real and tricky.

The Ecosystem in 2026

Open-source JSON diff is dominated by a handful of libraries. jsondiffpatch by Benjamin Eidelman, first published in 2012, is the de-facto JavaScript library: ~5k GitHub stars, supports objectHash, LCS arrays, reverse patches and a visual HTML formatter. json-diff by Andrey Tarantsov is the canonical Node CLI tool, with the same name shared by parallel implementations in Python, Go and Rust. DeepDiff by Sep Dehpour is the dominant Python library, recursive diff with options for ignoring order, ignoring numeric type changes, and a host of fine-grained controls. The Linux Foundation's JsonNode diffing in Jackson (Java) is the standard JVM choice. jq has no native diff command but its = and // operator family can express simple structural comparisons. VS Code's built-in diff handles JSON via text mode; the JSON Tools extension adds JSON-aware comparison. Online tools like Diffchecker offer JSON modes that are essentially the same recursive walk this tool implements, often layered on top of the same libraries.

Why Browser-Only Matters Here

Diffing two JSON payloads on a server requires uploading both. For ordinary public-data examples this is harmless. For API responses that contain authentication tokens, customer PII, internal employee records, configuration secrets, or unreleased product data, it is not. Even after the diff finishes, those payloads sit in server logs, possibly in a CDN cache, possibly in an analytics pipeline, possibly in a backup. A browser-only diff never transmits, the JSON is parsed and walked entirely in your tab. You can verify by opening DevTools' Network tab while you click Compare; there are no outbound requests. For comparing API responses against a baseline, debugging configuration drift between environments, or auditing changes in a lockfile that contains internal package URLs, "the JSON never leaves my device" is the architecture that makes the tool safe to use on real production data.

Frequently Asked Questions

Does key order affect the comparison?

No. JSON objects are unordered by RFC 8259 §4, so {"a":1, "b":2} and {"b":2, "a":1} are treated as identical. Only actual value differences are reported. This is the most useful default, if you want to compare key order, you actually want a text diff.

How are arrays compared?

By index, element 0 of the left input compared with element 0 of the right input, element 1 with element 1, and so on. Added or removed elements at the end are detected. The known limitation: an insertion or deletion near the front of a long array shifts every subsequent element, which produces a noisy diff. For arrays of objects with stable identity fields (id, uuid), an LCS-with-objectHash diff (jsondiffpatch with the objectHash callback) handles this case better; that is on the future feature list for this tool.

What happens with deeply nested objects?

The comparison is fully recursive. Nested objects and arrays at any depth are walked property by property. The output shows the full path to each difference (user.address.city, items[3].price). There is no practical depth limit beyond JavaScript's call-stack ceiling, which is in the thousands of frames on every modern engine.

Why does my big-integer comparison look wrong?

JavaScript parses every JSON number as a 64-bit IEEE 754 double. Above Number.MAX_SAFE_INTEGER (253 − 1 = 9,007,199,254,740,991), integers may lose precision silently. So a JSON file containing 9007199254740993 may compare as identical to a file containing 9007199254740992. This is a limitation of the underlying number representation, not the diff tool. If you are diffing data that contains 64-bit IDs (Twitter snowflake IDs, Discord IDs, large database keys), have your serialiser emit them as strings instead of numbers. Floating-point comparison has the same caveat: 0.1 + 0.2 is famously not exactly 0.3 in IEEE 754.

Can I compare JSON5 or JSONC (JSON with comments)?

Not directly. This tool uses the browser's built-in JSON.parse(), which strictly follows RFC 8259, comments, trailing commas, single-quoted strings, and unquoted keys are syntax errors. If your input is JSON5 (json5.org) or VS Code-style JSONC, strip the comments and trailing commas first, or run it through a tool like jsonc-parser to convert to strict JSON before pasting.

Is my JSON sent to a server?

No. Comparison runs entirely in your browser via JavaScript. Pasted JSON never crosses the network, verify in DevTools' Network tab while you click Compare, or take the page offline after it loads and confirm the diff still works. Safe for comparing API responses with auth tokens, configuration files with secrets, or database exports that contain customer PII.

Related Tools