Comparing two JSON files sounds simple until you try it with a regular text diff and realize that reordered keys, whitespace changes, and unsorted arrays produce thousands of false positives. Here are five methods for comparing JSON properly, ranked from quickest to most thorough.

Method 1: Browser-based semantic diff (fastest)

For one-off comparisons, paste both documents into our JSON Diff tool. It parses each side, walks the trees in parallel, and reports three kinds of differences: added (key exists on the right but not the left), removed (key exists on the left but not the right), and changed (value differs).

Because the comparison is semantic, key order doesn't matter and indentation is ignored. {"a":1,"b":2} and {"b":2, "a":1} are reported as identical. This is almost always what you want — JSON object key order is not significant per the spec.

Method 2: Pretty-print both, then text-diff

If you only have a text-diff tool available (e.g., your IDE, git diff, or VS Code's "Compare with…" feature), the trick is to pretty-print both files first with consistent indentation and sorted keys:

# Linux/macOS with jq
jq --sort-keys . file1.json > a.json
jq --sort-keys . file2.json > b.json
diff a.json b.json

The --sort-keys flag eliminates ordering differences. Without it, you'll see noise on every reordered object.

Method 3: Python's deepdiff library

For scripted comparisons, the deepdiff library handles edge cases that naive comparisons miss: floating-point tolerance, type coercion, array-element matching, and ignored paths.

from deepdiff import DeepDiff
import json

a = json.load(open('file1.json'))
b = json.load(open('file2.json'))
diff = DeepDiff(a, b, ignore_order=True)
print(diff)

The ignore_order=True option treats arrays as sets, which is right for lists of unordered items but wrong for ordered sequences. Set it explicitly based on what your data represents.

Method 4: jd (CLI tool for JSON diff)

The jd command-line tool produces patches in a format inspired by RFC 6902 (JSON Patch). It's useful when you want machine-readable output:

jd file1.json file2.json
# Output:
# @ ["status"]
# - "draft"
# + "published"

The @ lines show the path, - shows the old value, + shows the new value. You can apply the patch in reverse with jd -p patch.txt file2.json to get back to file1.json.

Method 5: JSON Patch (RFC 6902)

For API contexts where you need to send a diff over the wire — say, a PATCH request — JSON Patch is the standard format. Each operation is an object with op, path, and (for some operations) value:

[
  { "op": "replace", "path": "/status", "value": "published" },
  { "op": "add", "path": "/tags/-", "value": "json" },
  { "op": "remove", "path": "/draft" }
]

Libraries exist for every major language to generate and apply JSON Patches. This is the right format if your diff needs to be portable across systems.

Which method to use

For ad-hoc human inspection, the browser tool wins on speed. For CI pipelines that check whether a config file has drifted, jq --sort-keys piped into diff is the simplest dependency-free approach. For programmatic diffs in Python, deepdiff handles the edge cases. For wire-format patches between services, JSON Patch is the standard.

Common pitfalls

Three things trip people up. Floating-point precision: 0.1 + 0.2 isn't exactly 0.3; if your diff includes computed numbers, you may need a tolerance. Array order: JSON arrays are ordered, so [1,2,3] and [3,2,1] are different — but if your arrays represent unordered sets (like tags), you'll want to sort them before diffing. Number/string coercion: "42" and 42 are different types in JSON; a strict diff will flag them, which is usually correct.

For more on JSON's data model and where common errors come from, see our JSON data types guide and common JSON parsing errors.