DEV Community

Avinash Verma
Avinash Verma

Posted on • Originally published at jsonviewertool.com

How to Compare Two JSON Files (and Read the Diff Correctly)

Why stringify-equality lies, the gotchas that fool naive diffs (key order, array order, types), and how to read a semantic diff.

A test of mine once failed because two API responses "didn't match" -- except they did. The data was identical; the server had just serialized the keys in a different order. My assertion was JSON.stringify(actual) === JSON.stringify(expected), and that check is wrong more often than people realize. If you compare JSON -- for regression tests, config drift, or reviewing an API change -- here's how to do it correctly.

Why JSON.stringify(a) === JSON.stringify(b) lies

JSON objects are unordered by specification -- {"a":1,"b":2} and {"b":2,"a":1} represent the same data. But JSON.stringify preserves insertion order, so the two produce different strings and a string comparison reports a difference that isn't real:

// Order-sensitive -- falsely reports a difference
JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1});  // false

// Canonicalize keys recursively, THEN compare
function canonical(v) {
  if (Array.isArray(v)) return v.map(canonical);
  if (v && typeof v === "object") {
    return Object.keys(v).sort().reduce((o, k) => (o[k] = canonical(v[k]), o), {});
  }
  return v;
}
const equal = (a, b) => JSON.stringify(canonical(a)) === JSON.stringify(canonical(b));
Enter fullscreen mode Exit fullscreen mode

This sorts keys at every level so object reordering no longer counts as a change -- while keeping array order significant, which it should be.

The gotchas a naive diff trips on

  • Key order: objects are unordered; reordering is not a real change (but string equality says it is).
  • Array order: arrays are ordered -- [1, 2][2, 1]. Only sort them if you genuinely mean "set," not "list."
  • Type coercion: 1 (number) and "1" (string) are different in JSON. A loose compare that coerces them will miss a real change.
  • null vs missing: a key set to null is not the same as a key that's absent.
  • Number normalization: 1 vs 1.0, or float precision, can read as changes depending on the serializer.

Textual diff vs semantic diff

The single biggest mistake is using a line-by-line diff (like git diff) on JSON. Reformat or reorder the file and the entire thing lights up red. You want a semantic diff that compares by key path.

Comparing JSON correctly in code

In Python, sort keys for a canonical compare, or use DeepDiff for a real field-by-field report:

import json

# Naive string compare is order-sensitive too:
json.dumps({"a": 1, "b": 2}) == json.dumps({"b": 2, "a": 1})   # False

# Canonical compare -- sort keys at every level:
def equal(a, b):
    return json.dumps(a, sort_keys=True) == json.dumps(b, sort_keys=True)

# A real, path-level diff:
from deepdiff import DeepDiff
DeepDiff(old, new)   # -> {'values_changed': {...}, 'dictionary_item_added': [...]}
Enter fullscreen mode Exit fullscreen mode

A faster way: a visual semantic diff (no script)

When I just need to see what changed between two payloads -- in a code review or while debugging a failing test -- a visual diff beats writing a comparison script. Our free JSON Compare tool does a side-by-side semantic diff: it highlights added, removed, and changed values by path, ignores cosmetic reordering, and runs entirely in your browser (disclosure: I built it). For applying a known set of changes rather than just viewing them, JSON Patch (RFC 6902) is the structured counterpart.

FAQs

Does key order matter when comparing JSON?By spec, object keys are unordered, so reordering isn't a real change -- but JSON.stringify equality treats it as one. Use a canonical compare (sort keys first) or a semantic diff.

Is [1, 2] the same as [2, 1]?No -- array order is significant in JSON. Only sort both sides first if you're treating the array as an unordered set.

Why does my diff show everything as changed?Almost always reformatting or key reordering. Switch from a line-by-line diff to a semantic/structural one that compares by key path.

How do I compare two large JSON files?Use a semantic diff that reports changes by path (a tool, or DeepDiff in Python) rather than scrolling a line diff. Validate both files parse first.

Related tools

Top comments (0)