How to Compare JSON Objects: Finding Differences in JSON Data
Comparing JSON objects is one of the most common tasks developers face when working with APIs, configuration files and data pipelines. Whether you are debugging an unexpected API response, tracking configuration drift between environments, or reviewing a pull request that modifies a JSON schema, being able to quickly spot the differences between two JSON structures is essential. This guide covers the techniques, tools and pitfalls of JSON comparison.
Why Compare JSON?
JSON has become the universal data format for web development, and comparing JSON objects comes up in many everyday workflows:
- API response debugging. When an API starts returning unexpected data, comparing the current response against a known-good snapshot helps you identify exactly what changed. This is especially useful when dealing with third-party APIs where you have no control over the schema.
- Configuration drift. Modern applications often have configuration files for different environments (development, staging, production). Over time these files drift apart. Comparing them reveals missing keys, changed values and inconsistencies that can cause hard-to-diagnose bugs.
- Schema evolution. As your application evolves, your JSON schemas change. Comparing old and new versions helps you understand what fields were added, removed or renamed. This is critical for maintaining backward compatibility in APIs.
- Code review. When a teammate modifies a JSON fixture, translation file or package-lock.json, a structured diff is far more readable than a raw text diff. It highlights meaningful changes and filters out noise like key reordering.
What Makes JSON Comparison Tricky?
At first glance, comparing two JSON objects seems straightforward. But several characteristics of JSON make naive comparison unreliable:
- Key ordering. The JSON specification does not guarantee key order in objects.
{"a":1,"b":2}and{"b":2,"a":1}are semantically identical. A plain string comparison would flag them as different. - Nested objects. JSON supports deeply nested structures. A change three levels deep should still be detected and reported with its full path, like
user.address.city. - Array ordering. Arrays in JSON are ordered by definition. But in practice, some arrays represent sets (where order does not matter) while others represent sequences (where order does matter). Deciding how to compare arrays depends on the context.
- Type coercion. The string
"42"and the number42are different JSON types. A good diff tool should flag this as a type change, not just a value change. - Null vs. missing keys. There is a semantic difference between a key being present with a
nullvalue and the key being absent entirely. Some diff tools treat these the same, but they have different implications in many APIs.
Types of JSON Diff
Not all JSON diffs are created equal. Depending on your use case, you may need different comparison strategies:
Structural Diff
A structural diff compares the shape of two JSON documents. It focuses on which keys exist, the types of values and the nesting hierarchy. This is useful when you want to check if two APIs return the same shape of data, regardless of the actual values.
Semantic Diff
A semantic diff ignores superficial differences like key ordering and whitespace. It compares the parsed data structures directly. This is the most common type of diff for day-to-day development work.
Patch Format (RFC 6902)
RFC 6902 defines JSON Patch, a standardized format for describing changes to a JSON document. A patch is itself a JSON array of operations:
[
{ "op": "replace", "path": "/name", "value": "Jane" },
{ "op": "add", "path": "/email", "value": "jane@example.com" },
{ "op": "remove", "path": "/oldField" }
]
Supported operations include add, remove, replace, move, copy and test. This format is machine-readable and can be applied programmatically to transform one JSON document into another.
How to Compare JSON in JavaScript
JavaScript offers several approaches for comparing JSON objects, ranging from simple to robust.
Using JSON.stringify
The simplest approach is to serialize both objects to strings and compare:
const isEqual = (
JSON.stringify(obj1) === JSON.stringify(obj2)
);
This works for simple cases but fails when keys are in different order. You can sort keys first by passing a replacer function, but this still does not handle nested arrays or provide a useful diff output.
Deep Comparison with Recursion
For a proper comparison that reports specific differences, you need a recursive approach:
function jsonDiff(a, b, path = "") {
const diffs = [];
const keysA = Object.keys(a);
const keysB = Object.keys(b);
for (const key of keysA) {
const fullPath = path ? path + "." + key : key;
if (!(key in b)) {
diffs.push({ path: fullPath, type: "removed" });
} else if (typeof a[key] === "object") {
diffs.push(...jsonDiff(a[key], b[key], fullPath));
} else if (a[key] !== b[key]) {
diffs.push({ path: fullPath, type: "modified",
oldValue: a[key], newValue: b[key] });
}
}
for (const key of keysB) {
if (!(key in a)) {
const fullPath = path ? path + "." + key : key;
diffs.push({ path: fullPath, type: "added" });
}
}
return diffs;
}
This function walks both objects recursively, collecting differences with their full paths. It correctly handles nested objects and reports added, removed and modified keys. For production use, you would also want to handle arrays, null values and type mismatches.
How to Compare JSON in Python
Python makes JSON comparison straightforward thanks to its built-in dictionary comparison. Since Python dictionaries already ignore key order by default, a simple equality check works:
import json
with open("old.json") as f:
old = json.load(f)
with open("new.json") as f:
new = json.load(f)
print(old == new) # True if identical
For detailed diffs, the deepdiff library is the most popular choice:
from deepdiff import DeepDiff
diff = DeepDiff(old, new, ignore_order=True)
print(diff)
# Output:
# {'values_changed': {"root['name']": {
# 'new_value': 'Jane', 'old_value': 'John'}}}
The deepdiff library supports ignoring array order, excluding specific paths, handling custom objects and generating machine-readable output. The ignore_order=True flag is particularly useful when comparing arrays that represent unordered sets.
Reading JSON Diff Output
Understanding diff output is just as important as generating it. Most JSON diff tools use a consistent set of change types:
- Added keys are properties that exist in the new JSON but not in the old. These are typically highlighted in green.
- Removed keys are properties that exist in the old JSON but not in the new. These are typically highlighted in red.
- Modified values are properties that exist in both documents but with different values. These show the old and new value side by side, often in yellow or orange.
- Moved keys are properties that appear at a different path in the new document. Not all diff tools detect moves, as it requires heuristic matching.
Color coding makes visual scanning much faster. Side-by-side views are generally more readable than inline diffs for JSON data, because they preserve the structure of both documents. When reviewing a diff, start by looking at the summary (total number of changes by type), then drill into specific paths that are relevant to your investigation.
Common Pitfalls
Even with good tools, there are several gotchas to watch out for when comparing JSON:
- Floating point precision. The number
0.1 + 0.2produces0.30000000000000004in JavaScript. If one system serializes this as0.3and another as0.30000000000000004, a diff will flag it as changed even though the values are practically equal. Consider using epsilon-based comparison for numeric fields. - Date format inconsistencies. The same timestamp can be represented as
2026-03-25T00:00:00Z,2026-03-25T00:00:00.000Zor1742860800. These are semantically equivalent but will appear as differences in a naive comparison. - Whitespace and formatting. Pretty-printed JSON with 2-space indentation and minified JSON are identical when parsed, but a text-based diff will show every line as changed. Always parse JSON before comparing, never compare raw strings.
- Character encoding. Unicode characters can be represented as literal characters or escape sequences. For example,
"\u00e9"and"\u00e9"are the same character. Normalize encoding before comparison to avoid false positives. - Large files and performance. Recursive deep comparison has O(n) complexity for flat objects, but deeply nested structures with large arrays can be slow. For JSON files larger than a few megabytes, consider streaming parsers or diffing specific subtrees instead of the entire document.
Compare JSON objects instantly
Paste two JSON documents side by side and see every added, removed and modified key highlighted in real time. No data leaves your browser.
Open JSON Diff Tool