Quick answer: Normalize both files first (sort keys, same indentation), then diff them. In the browser: format each file with Sort Keys on, then compare side by side. On the command line:
diff <(jq -S . a.json) <(jq -S . b.json). For a report of changed paths only, use Python's DeepDiff.
Two API responses that should match. A config file before and after a deploy. A database export from Monday and one from Friday. You throw both into a diff tool and get 400 highlighted lines, almost all of them noise: keys in a different order, two-space versus four-space indentation, a timestamp that changed because of course it did.
Comparing JSON is harder than comparing ordinary text because JSON has rules about what counts as the same. This guide covers those rules first, then five ways to compare files that respect them, from a thirty-second browser method to tooling for multi-megabyte exports.
Use JSON Compare to inspect added, removed, and changed values in two non-sensitive sample documents.
Why Text Diff Tools Lie About JSON
These two documents are identical as data:
// a.json
{"name": "Widget", "price": 9.5, "tags": ["new", "sale"]}
// b.json
{
"tags": ["new", "sale"],
"price": 9.50,
"name": "Widget"
}
A line-based diff reports every line as changed. Three things cause the noise:
- Key order. The JSON spec says object keys are unordered. Most serializers emit them in insertion order, which differs between systems.
- Whitespace. Indentation, line endings (CRLF vs LF), and a trailing newline are all invisible to the parser but visible to
diff. - Number formatting.
9.5,9.50, and9.5e0parse to the same value.
One thing that is not noise: array order. [1, 2] and [2, 1] are different JSON. Any tool that ignores array order is making an assumption about your data, so check its defaults. For the background, see JSON array vs object.
The fix for all of it is the same: normalize, then compare. Every method below is a variation on that idea.
Method 1: Sort Keys and Compare in Your Browser
Fastest option when you have two payloads on your clipboard and no tools installed. It also keeps the data on your machine, which matters when the files contain customer records.
- Open JSON Prettifier and paste the first file.
- Turn on Sort Keys, pick an indentation, and click Format. Copy the output.
- Repeat for the second file with the same settings.
- Paste both outputs into a side-by-side diff: two VS Code tabs with Compare, or any text diff page.
Because both documents now have identical key order and whitespace, only genuine value changes are highlighted. If either file refuses to format, it is invalid; the validator shows the line and our parse error guide explains the message.
Method 2: Compare in VS Code
If both files are already on disk, VS Code has a built-in diff view.
- In the Explorer, click the first file, then Ctrl-click (Cmd-click on Mac) the second.
- Right-click and choose Compare Selected.
- Before trusting the result, open each file and run Format Document (Shift+Alt+F / Shift+Option+F) so indentation matches.
VS Code does not sort keys natively. Install a "Sort JSON" extension or pre-sort with jq (next method). The VS Code JSON guide covers the useful extensions.
Method 3: jq on the Command Line
jq -S sorts keys recursively and prints with consistent indentation. Combined with diff it gives a clean, scriptable comparison:
# Side-by-side, only real changes
diff <(jq -S . a.json) <(jq -S . b.json)
# Unified diff with colour (git is usually installed anyway)
git diff --no-index <(jq -S . a.json) <(jq -S . b.json)
# Just answer yes/no, exit code 0 when equal
jq -n --slurpfile a a.json --slurpfile b b.json '$a == $b' -e > /dev/null && echo same || echo different
Two refinements that save time in practice. Ignore volatile fields before comparing:
diff <(jq -S 'del(.updatedAt, .requestId)' a.json) <(jq -S 'del(.updatedAt, .requestId)' b.json)
And compare arrays as sets when order is not meaningful in your data:
diff <(jq -S '.items |= sort_by(.id)' a.json) <(jq -S '.items |= sort_by(.id)' b.json)
On Windows, process substitution <( ) works in Git Bash and WSL. In PowerShell, write each sorted output to a temp file first and run Compare-Object or git diff --no-index.
Method 4: Python DeepDiff for a Change Report
When you need to know what changed rather than see highlighted lines, DeepDiff returns a structured result you can log, assert on in tests, or feed into a script:
# pip install deepdiff
import json
from deepdiff import DeepDiff
with open("a.json") as f, open("b.json") as g:
a, b = json.load(f), json.load(g)
diff = DeepDiff(
a, b,
ignore_order=True, # treat arrays as unordered (remove if order matters)
exclude_paths=["root['updatedAt']"],
significant_digits=2, # 9.5 == 9.50 == 9.499
)
print(diff.pretty() if diff else "identical")
Sample output:
Value of root['price'] changed from 9.5 to 10.0.
Item root['tags'][2] added to iterable.
Key root['sku'] removed from dictionary.
That reads like a changelog, which is exactly what you want when comparing an API response against a recorded fixture in a test suite. Without any library, a == b on the two loaded dicts gives a plain equality check, since Python dict comparison ignores key order.
Method 5: A Dedicated JSON Diff CLI
For CI pipelines and shell scripts, a purpose-built tool prints a compact structural diff and sets a meaningful exit code:
# Node.js
npx json-diff a.json b.json
# Go, single binary
jd a.json b.json
jd -set a.json b.json # compare arrays as sets
json-diff output looks like a unified diff but at the key level, so a moved key produces no noise. jd can also emit and apply patches in JSON Patch (RFC 6902) format, useful when the comparison result needs to be stored or replayed.
Choosing a Method
| Situation | Use | Handles key order? | Handles array order? |
|---|---|---|---|
| Two payloads on clipboard, sensitive data | Browser sort + diff | Yes (Sort Keys) | Order is preserved and compared |
| Files in a project | VS Code Compare | With extension | Preserved |
| Shell scripts, large files | jq -S + diff | Yes | Preserved; sort_by to ignore |
| Test assertions, change reports | Python DeepDiff | Yes | Configurable (ignore_order) |
| CI gate with exit code | json-diff / jd | Yes | Configurable (-set) |
Mistakes That Produce Wrong Answers
- Comparing before validating. A truncated file diffs as "everything after line 300 removed". Validate both inputs first; for multi-megabyte exports see validating large JSON in the browser.
- Ignoring array order by default.
ignore_order=Truehides a real bug when the array is a sorted list of steps or a ranked result set. - Float equality.
0.1 + 0.2serialized from one language and0.3from another are not equal. Use a tolerance (significant_digits) when values come from arithmetic. - Dates in different formats.
"2026-09-15T10:00:00Z"and1789466400are the same instant but will never match textually. Standardize on one format; see JSON date format. - Uploading production data to a diff website. Many online JSON diff tools post both files to a server. Check the network tab, or use a client-side tool and a local diff.
If equivalent objects produce different digests, use these JSON canonicalization checks for reliable hashes before changing your comparison or signing logic.