Developer Tools

How to Compare Two JSON Files?

The right way to compare two JSON files is a semantic diff that ignores key order and whitespace — not a plain text diff. Here are the exact jq, jd, and Python commands, a method-by-method comparison table, and when each one wins.

By Inventive HQ Team

The correct way to compare two JSON files is a semantic (structural) diff that ignores key order and whitespace — not a plain text diff. JSON objects are unordered by definition, so {"a":1,"b":2} and {"b":2,"a":1} are the same data, and a byte-for-byte tool like Unix diff will wrongly report them as different. The quickest reliable command is diff <(jq -S . a.json) <(jq -S . b.json), which sorts keys and normalizes formatting in both files so only real value changes remain. For a dedicated structural diff, jd a.json b.json prints just the paths that changed; in code, use a deep-equality helper (assert.deepStrictEqual, lodash _.isEqual, Python deepdiff) rather than ===.

That's the summary an AI overview gives you. What it can't give you is the part that actually saves you an afternoon: why a plain diff lies to you about JSON, exactly which flags make each tool ignore the right things, and a side-by-side table of every method so you can pick the one that fits your file — a two-line config or a five-gigabyte export.

Textual vs. semantic: the one distinction that matters

Almost every "why does my JSON diff show changes that aren't there?" problem comes down to a single confusion. There are two fundamentally different things a tool can compare:

  • Textual diff treats the files as plain text. It compares bytes and lines and has no idea it's looking at JSON. Reorder keys, reindent, or add a trailing newline and it reports a difference — because the text really did change, even though the data didn't.
  • Semantic (structural) diff parses both files into data structures first, then compares those structures. It ignores whitespace, indentation, and object key order, and reports only genuine changes: a value that changed, a key that was added, a key that was removed.
Textual diff vs semantic diff on reordered JSON Two JSON snippets holding the same data in different key order. A textual diff flags them as different; a semantic diff reports them as equal. Same data, different key order { "id": 7,   "name": "a" } a.json { "name": "a",   "id": 7 } b.json Textual diff DIFFERENT (false alarm) bytes differ Semantic diff EQUAL (correct) same structure

One caveat that trips people up: object key order is not meaningful in JSON, but array order is. {"a":1,"b":2} equals {"b":2,"a":1}, but [1,2] does not equal [2,1]. A good semantic diff respects that distinction by default and only ignores array order when you explicitly ask it to.

Which method should I use? (comparison table)

MethodTypeIgnores key order?Ignores whitespace?Ignores array order?Best for
diff a.json b.jsonTextualNoNoNoFiles already normalized to identical formatting; quick literal change check
diff <(jq -S . a) <(jq -S . b)Semantic (normalized text)YesYesOptional (sort first)The everyday CLI default; no extra tools beyond jq
jd a.json b.jsonStructuralYesYesOptional (-set)Clean, path-based diff output; can also emit a patch
json-diff a.json b.json (npm)StructuralYesYesNoColorized side-by-side structural diff
Python deepdiffStructural (in code)YesYesOptional (ignore_order=True)Scripts, test assertions, tolerant numeric/order rules
_.isEqual / assert.deepStrictEqualDeep equal (in code)YesYesNoJS/Node unit tests and app logic
jsondiff.com / editor diffVisualYes (semantic tools)YesNoEyeballing differences; quick one-off — not for sensitive data

The decision rule: reach for the jq -S one-liner by default, upgrade to jd when you want readable path-based output or a patch you can apply, and drop into deepdiff or a deep-equal helper when the comparison lives inside a script or test.

Advertisement

The command-line workflow, step by step

The most portable approach normalizes both files, then diffs the normalized output. Every real difference survives; every formatting and key-order difference disappears.

The semantic diff pipeline Two raw JSON files are each normalized with jq sort-keys, then compared with diff to produce only the real differences. Normalize, then diff a.json raw b.json raw jq -S . sort keys + reformat diff real changes only

1. The one-liner (bash / zsh). Process substitution feeds two normalized streams straight into diff:

diff <(jq -S . a.json) <(jq -S . b.json)

-S (--sort-keys) sorts every object's keys and jq's pretty-printer standardizes indentation, so key order and whitespace can no longer create false differences. Add -u to diff for unified context, or pipe to colordiff for color.

2. Handle arrays whose order isn't meaningful. Sort them before diffing. For arrays of scalars, sort recursively:

diff <(jq -S 'walk(if type=="array" then sort else . end)' a.json) \
     <(jq -S 'walk(if type=="array" then sort else . end)' b.json)

For arrays of objects, sort by a stable identity key so records line up:

jq -S 'sort_by(.id)' a.json > /tmp/a.sorted.json
jq -S 'sort_by(.id)' b.json > /tmp/b.sorted.json
diff /tmp/a.sorted.json /tmp/b.sorted.json

3. Prefer a structural diff tool. jd gives cleaner, path-based output and can emit a patch:

jd a.json b.json          # human-readable structural diff
jd -set a.json b.json     # treat arrays as unordered sets
jd -o patch.diff a.json b.json   # write a diff you can later apply

The npm package json-diff is a good alternative for colorized side-by-side output (json-diff a.json b.json).

Loading interactive tool...

Comparing JSON in code

For scripts and tests, compare the parsed data — never the raw strings.

Python. json.load both files and compare with == (dict key order doesn't affect equality). For a detailed report of what changed, use deepdiff:

import json
from deepdiff import DeepDiff

a = json.load(open("a.json"))
b = json.load(open("b.json"))

print(a == b)                              # True/False, order-insensitive for keys
print(DeepDiff(a, b, ignore_order=True))   # exactly what changed, arrays as sets

JavaScript / Node. === only checks reference identity for objects, so it's useless here. Use a deep-equality helper:

const _ = require("lodash");
const a = require("./a.json");
const b = require("./b.json");

_.isEqual(a, b);                    // true/false, deep + key-order-insensitive
// In tests:
const assert = require("node:assert");
assert.deepStrictEqual(a, b);       // throws with a diff on mismatch

The gotchas that cause false differences

Even with a semantic diff, a handful of data-level issues produce differences that look real but aren't:

  • Numeric precision. 1.0 vs 1, or floats that differ in the last bit, can flag as changed. In deepdiff, set significant_digits=; elsewhere, round or compare with a tolerance.
  • Null vs. missing. {"x": null} is not the same as {}. Decide which your comparison should treat as equal and normalize before diffing.
  • String-encoded values. "7" (string) vs 7 (number), or dates stored in different formats, are genuinely different values. Coerce or canonicalize types first if your data mixes them.
  • Unicode normalization. Visually identical strings with different Unicode encodings compare as different; normalize (e.g. NFC) if you ingest text from mixed sources.

Bottom line

Comparing JSON is not really about picking a tool — it's about picking the type of comparison. Choose semantic over textual, remember that object key order is noise but array order is signal, and normalize both files before you diff. Start with diff <(jq -S . a.json) <(jq -S . b.json), graduate to jd when you want readable structural output, and move into deepdiff or a deep-equal assertion when the comparison lives in your test suite. Do that and the differences your tool reports will be the ones that actually matter.

Frequently Asked Questions

How do I compare two JSON files?

Use a semantic (structural) diff, not a plain text diff. The fastest command-line method is to normalize both files with jq and diff the result: diff <(jq -S . a.json) <(jq -S . b.json). The -S flag sorts every object's keys so that two files with the same data but different key order compare as equal. For a purpose-built structural diff, install jd and run jd a.json b.json, which prints only the paths that actually changed. A plain diff a.json b.json also works, but only if both files use identical key order and formatting — otherwise it reports differences that don't exist.

What is the difference between a textual and a semantic JSON diff?

A textual diff (like Unix diff) compares the files byte by byte, line by line — it has no idea it is looking at JSON. Reorder the keys, change the indentation, or add a trailing newline and it screams "different" even though the data is identical. A semantic (structural) diff parses both files into data structures first, then compares those structures, so it ignores whitespace, indentation, and key order and reports only real changes to values, added keys, or removed keys. For JSON, semantic diff is almost always what you want; textual diff is only reliable when both files are already normalized to the exact same format.

Does key order matter when comparing JSON?

Not semantically. The JSON specification (RFC 8259) defines an object as an unordered collection of name/value pairs, so {"a":1,"b":2} and {"b":2,"a":1} are the same object. Most parsers and semantic diff tools treat them as equal. But key order absolutely matters to a textual diff, which sees two different byte sequences. That mismatch is the single most common cause of false differences when people compare JSON with plain diff. Array order, by contrast, is significant in JSON — [1,2] and [2,1] are genuinely different unless you deliberately tell your tool to treat arrays as sets.

How do I compare two JSON files in jq?

Normalize both files and diff them: diff <(jq -S . a.json) <(jq -S . b.json). The -S (--sort-keys) flag sorts object keys and jq's pretty-printer standardizes whitespace, so only real value changes survive. If your arrays may be in different orders but the order is not meaningful, sort them first — for arrays of scalars use jq -S 'sort' or, recursively, jq -S 'walk(if type=="array" then sort else . end)' (walk requires jq 1.6+). For arrays of objects, sort by a stable key with sort_by(.id) before diffing.

How do I compare JSON while ignoring array order?

Sort the arrays before diffing, or use a tool that can treat arrays as sets. With jd, pass -set to compare arrays as unordered sets: jd -set a.json b.json. With jq, sort arrays of scalars using sort, or arrays of objects using sort_by(.id), so both files land in a canonical order before you diff them. In Python, the deepdiff library has an ignore_order=True option that does this for you. Only ignore array order when order is genuinely not meaningful in your data — in most JSON, array order carries meaning.

How do I compare two JSON files in VS Code?

Select both files in the Explorer, right-click the first, choose "Select for Compare", then right-click the second and choose "Compare with Selected". VS Code opens a side-by-side diff. Note that the built-in editor diff is textual, so format both files identically first (VS Code's "Format Document" on each, or run them through jq -S) or you'll see whitespace and key-order noise. Extensions such as "Partial Diff" and dedicated JSON-diff extensions add structural comparison that ignores formatting.

How do I compare large JSON files that won't fit in memory?

Avoid tools that load the whole document into RAM. Stream both files through jq (which processes incrementally) to normalize them, write the sorted output to disk, then run a line-based diff on the two normalized files — Unix diff itself is memory-efficient and streams. For multi-gigabyte files, sort each file's records by a stable key first so diff can work line by line, and consider splitting by top-level key. Language-native approaches should use streaming parsers (Python's ijson, Jackson's streaming API in Java) rather than json.load, which reads everything at once.

What is the best online tool to compare JSON?

jsondiff.com is a widely used semantic JSON compare tool that ignores formatting and highlights only real differences. jsoncrack.com visualizes JSON as a node graph, which helps you eyeball structural differences. Our own Diff Checker below runs entirely in your browser. Important caveat: never paste secrets, credentials, personal data, or proprietary payloads into a third-party online diff tool — you don't control where that data goes. For anything sensitive, use a local tool like jq, jd, or your editor's built-in diff.

How do I compare two JSON objects in code?

In JavaScript, don't use === (it only checks reference identity for objects). Use a deep-equality function such as lodash's _.isEqual(a, b), Node's assert.deepStrictEqual(a, b), or a recursive comparison you write yourself. In Python, json.load both files and compare with == — Python's dict and list equality is already deep and order-insensitive for dict keys — or use deepdiff's DeepDiff(a, b) to get a structured report of exactly what changed. For test assertions, deep-equality helpers give you a clear failure message showing the differing path.

JSON comparisondata validationfile comparisondevelopment tools