JSON & Data
How to Diff Two JSON Files and Actually See What Changed
Comparing JSON by eye is painful and text diffs choke on key order. Learn how structural JSON diffing works and spot every added, removed or changed value.
Try the toolJSON Diff →Why comparing JSON is harder than it looks
You have two versions of a config file, an API response before and after a deploy, or a fixture that a test suddenly disagrees with. You need one question answered: what actually changed? The obvious move is to drop both blobs into a plain text diff, but that falls apart fast. A text diff cares about byte-for-byte layout, so it flags reordered keys, changed indentation, and trailing commas as "differences" even when the two documents are semantically identical.
JSON is a tree of values, not lines of text. To compare it meaningfully you have to walk that tree and compare values by path, ignoring cosmetic noise like key order and whitespace.
How a structural JSON diff works
A structural diff parses both inputs into objects, then recursively compares them. At each node it decides one of four things: the value is unchanged, it was added (present on the right, missing on the left), removed (present on the left, missing on the right), or changed (present on both with a different value). Objects are matched by key; arrays are usually matched by index.
Here is the core idea in a few lines of JavaScript:
function diff(a, b) {
if (a === b) return undefined; // identical primitives
if (typeof a !== 'object' || a === null ||
typeof b !== 'object' || b === null) {
return { from: a, to: b }; // changed leaf
}
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
const out = {};
for (const k of keys) {
const d = diff(a[k], b[k]);
if (d !== undefined) out[k] = d;
}
return Object.keys(out).length ? out : undefined;
}Feed it two objects and you get back only the branches that differ, which is exactly what your eyes were trying to find.
A practical walkthrough
Say you deployed a change and want to compare the old and new settings payloads:
// left (before) // right (after)
{ {
"name": "api", "name": "api",
"replicas": 2, "replicas": 3,
"debug": true, "region": "eu-west-1",
"region": "us-east-1" "region": "eu-west-1"
} }Run both sides through JSON Diff and the result is unambiguous: replicas changed from 2 to 3, region changed from us-east-1 to eu-west-1, and debug was removed. Notice that reordering the keys did not create a single false positive. Everything runs in your browser, so even production configs never leave your machine.
Common pitfalls to watch for
- Arrays are compared by index, not identity. Inserting one element at the front of a list makes every later item look "changed" because each index now points at a different value. If order does not matter to you, sort both arrays first.
- Types matter. The string
"3"and the number3are a real difference, and a good diff will flag it. This is often the actual bug when an API starts returning stringified numbers. - Floating point noise.
0.1 + 0.2serializes to0.30000000000000004. If one side computed a value and the other hard-coded it, expect a diff you did not intend. - Invalid JSON in, garbage out. A trailing comma or a smart quote will stop the parse before any comparison happens. If a side will not load, paste it into the JSON Validator to find the exact line and column first.
Tips for cleaner comparisons
Before diffing, it helps to normalize both documents. Running each side through the JSON Formatter gives them consistent indentation and makes the changed region easier to scan once the tool highlights it. If you would rather compare the raw text line by line (for example, to inspect exact formatting), the Text Diff Checker is the right tool for that job.
Conclusion
A structural diff answers a different question than a text diff: not "which bytes moved" but "which values changed." That distinction is what turns a noisy wall of red and green into a short, honest list of adds, removes, and changes. Paste your two documents, read the highlighted result, and move on with confidence.