How to compare JSON objects
June 23, 2026 · 13 min read
Comparing two JSON blobs sounds trivial until production proves otherwise: whitespace differs, keys arrive in another order, numbers are numerically equal but textually distinct, and nested arrays encode business meaning by position. A line-by-line diff of pretty-printed files often wastes review time on noise.
The fix is to separate presentation from semantics. Parse both inputs into values, normalize predictable fields, then run a structural compare that understands JSON types. This guide walks through that pipeline with patterns you can reuse in tests, CI, and support tooling.
Why string compare fails
Two objects can be semantically identical while their serialized strings differ: {"a":1,"b":2} versus {"b":2,"a":1}. String equality returns false even though parsers produce the same structure. The same trap appears with insignificant whitespace and escaped Unicode.
Floating-point literals add another layer: 0.1 + 0.2 rarely equals 0.3 as a binary float. If your domain treats numbers as decimals, compare with a decimal library or compare string forms after canonical formatting.
Normalize first
Pick a canonical form before comparing: sort object keys recursively, trim strings if business rules allow, coerce known date fields to UTC ISO strings, and map empty arrays to null only if your API contract says so. Document these rules in your test suite so future contributors do not “fix” tests by deleting normalization.
For API regression tests, store expected JSON as parsed objects (or normalized strings), not as copy-pasted pretty prints from Postman. That single habit removes hundreds of flaky failures when field order changes but behavior does not.
function sortKeys(value) {
if (Array.isArray(value)) return value.map(sortKeys);
if (value && typeof value === "object") {
return Object.fromEntries(
Object.keys(value).sort().map((k) => [k, sortKeys(value[k])])
);
}
return value;
}
const a = { b: 2, a: 1 };
const b = { a: 1, b: 2 };
JSON.stringify(sortKeys(a)) === JSON.stringify(sortKeys(b)); // true
Deep equality rules
Deep equality walks both structures in parallel: matching types at each node, equal primitives, object keys with the same sets and values, and arrays compared element-wise unless you explicitly treat arrays as unordered bags (rare and dangerous without schema).
Decide how to treat missing versus null fields. JSON Schema’s required array is one source of truth; OpenAPI examples are not. Two payloads that look alike in a diff tool may not be equal under your API’s nullability rules.
Arrays and ordering
Order matters for JSON arrays unless your contract says otherwise. Event timelines, sortable lists, and matrix rows should use ordered comparison. For “set of tags” semantics, sort a copy of both arrays by a stable key before comparing, or compare multisets with counts.
When items are objects with ids, index by id first, then compare each pair. That turns an O(n²) scan into a map lookup and yields human-readable per-id diffs instead of “line 47 changed” noise.
A reliable workflow
In development: paste left and right JSON into a structural compare tool, scan the path list, and fix the first real mismatch. In CI: parse, normalize, deep-equal, and on failure emit a minimal patch or JSON Pointer paths for logs.
Keep a small golden-file library of tricky cases: unicode escapes, large integers as strings, empty objects versus missing keys, and duplicate keys (invalid JSON but sometimes produced by buggy serializers). Your compare pipeline should reject invalid JSON early with actionable errors.
FAQ
- Does key order matter in JSON?
- For equality, no - objects are unordered maps. For string diffs of raw text, yes. Always parse before comparing semantics.
- How do I ignore specific fields?
- Delete or mask those paths during normalization, or compare with a schema-aware tool that supports ignore lists.
- Should I compare numbers as strings?
- Only if your API stores decimals as strings by design. Otherwise compare numeric values and document float tolerance if needed.
- What about duplicate keys in JSON?
- Standard parsers reject or last-key-wins depending on the library. Fix the producer; do not rely on ambiguous documents.