Skip to content
jsonbeautifiers
English

JSON Diff

Compare two documents by structure, so reformatting and key order are invisible.

Original
Changed

Nothing you paste leaves your browser. The connect-src allowlist makes that a browser guarantee rather than a promise. Check it yourself

This compares two documents by structure rather than by line. Reformat one of them, sort its keys, change its indentation: the diff stays empty, because none of that changed the data.

A text diff on JSON is close to useless for exactly that reason. Reserialise a document with a different library and every line reports as changed while nothing actually did.

What counts as a difference

Four kinds of change, each reported with a JSON Pointer to the exact location.

Added
A key or element present on the right and not on the left.
Removed
Present on the left and not on the right.
Changed
Present in both with a different value of the same type.
Retyped
Present in both with a different type. Worth separating, because a number that became a string is usually a serialisation bug rather than a data change.

How arrays are compared, and why it matters

Arrays are the hard part of any structural diff, and there is no single right answer.

Comparing position by position is correct for a fixed-shape tuple and catastrophic for a list. Insert one element at the front of a thousand-element array and every position after it reports as changed, which buries the one real difference under a thousand false ones.

This tool runs a longest-common-subsequence pass instead, so an insertion is reported as an insertion. That costs time proportional to the product of the two lengths, so above a threshold it falls back to positional comparison and says in the notes that it did. It never silently degrades.

Things that are deliberately not differences

Key order
JSON objects are unordered by specification. Two documents with the same members in a different order are the same document.
Whitespace and indentation
Insignificant to a parser, so invisible here.
0 and -0
Distinct under Object.is but identical as JSON numbers.

How to do this in code

Structural comparison in code.

sh jq

The first line is the one to remember. Sorting keys first removes most of the noise from a text diff.

# Sort keys recursively, then diff the text. Cheap and
# surprisingly effective for small documents.
diff <(jq -S . a.json) <(jq -S . b.json)

# Keys present in one and not the other
jq -n --slurpfile a a.json --slurpfile b b.json \
  '($a[0] | paths) - ($b[0] | paths)'
py Python
from deepdiff import DeepDiff

diff = DeepDiff(a, b, ignore_order=True)
print(diff)

# Standard library only, for a shallow comparison
changed = {k for k in a.keys() | b.keys() if a.get(k) != b.get(k)}
js JavaScript

JSON Patch is the standard wire format for a JSON diff, and the paths are RFC 6901 pointers like the ones this tool reports.

import { compare } from 'fast-json-patch';

// RFC 6902 JSON Patch: a list of operations that turns a into b
const patch = compare(a, b);
// [{ op: 'replace', path: '/user/name', value: 'Priya' }]
go Go

go-cmp is the standard choice in Go tests and produces readable output for nested structures.

import "github.com/google/go-cmp/cmp"

if d := cmp.Diff(a, b); d != "" {
    t.Errorf("mismatch (-want +got):\n%s", d)
}

Questions

Why does reordering keys show no difference?
Because RFC 8259 defines an object as an unordered collection. Every parser in practice preserves insertion order, and diffs that depend on it are testing serialisation rather than data.
Can I ignore fields like timestamps?
Yes. Ignoring a path removes it from the comparison entirely, which is how you compare two API responses that differ only in requestId and generatedAt.
What is a JSON Pointer?
RFC 6901: a slash-separated path such as /users/0/email. Two characters need escaping inside a key: ~ becomes ~0 and / becomes ~1. Every change reported here carries one, so you can address the location programmatically.