Compare two JSON structures

compare two JSON structures and list additions, removals and modifications, key by key

Why compare two JSON documents?

Comparing two JSON structures comes up regularly in a developer's life. An API response that changes after an update. A configuration file that diverges between two environments. An export of objects that has to align with a reference. A JSON diff answers exactly this question: what was added, removed or modified, and where?

A line-by-line diff (like git diff) is often not enough. If the formatting differs (whitespace, key order), the text diff flags hundreds of lines while the data structure is identical. A JSON comparator works on the structure once parsed, which removes that noise and reveals only the semantic differences.

The diff format produced by the tool

For each difference, the tool returns:

  • a path in simplified JSONPath format, for example $.user.address[0].city;
  • a type among added (added on the right), removed (present on the left only), modified (different values);
  • the left value and/or the right value depending on the type.

An empty diff means the two JSON documents are structurally identical, regardless of their formatting or key order.

How the algorithm walks the two structures

The algorithm is recursive. At each level, it identifies the type of the two compared values:

  • If both are associative objects, it takes the union of the keys. For each key, it recurses, or marks added/removed if the key only exists on one side.
  • If both are ordered arrays, it compares position by position. A difference at the start of an array can shift everything else, which produces a verbose diff: it is an accepted limitation of naive structural diff.
  • If the types differ (object versus array, scalar versus null), it is marked modified.
  • If both values are scalars (string, number, boolean, null), a simple strict comparison is enough.

The key order in an object does not count: {"a": 1, "b": 2} and {"b": 2, "a": 1} produce an empty diff. This is consistent with JSON semantics, where order is not significant. On the other hand, the element order in an array counts: an array is ordered by construction.

A concrete example

Here are two versions of a user object:

// left
{
  "id": 42,
  "name": "Alice",
  "roles": ["admin", "editor"]
}

// right
{
  "id": 42,
  "name": "Alice Martin",
  "roles": ["admin", "viewer"],
  "active": true
}

The diff produced:

  • $.name: modified, "Alice""Alice Martin"
  • $.roles[1]: modified, "editor""viewer"
  • $.active: added, true

Use cases

  • Environment diff: compare the output of an endpoint in pre-production and in production. Very useful during a migration or a cache refresh.
  • Migration audit: compare an export before and after transformation to check that no field has been lost.
  • API regression: before and after a change, compare the response for an identical request. An empty diff confirms non-regression.
  • Configuration sync: compare composer.json between two branches, two .eslintrc files, two Symfony configurations.
  • Snapshot tests: replace a line-by-line comparison with a structural comparison in an integration test suite.

Limits of structural diff

Comparing ordered arrays is a known limit of naive structural diffs. If you insert an element at the start of an array, all following positions are shifted and the diff flags every difference as a modification. For such cases, more advanced algorithms exist (Myers, Patience, natural-key diff), but they fall outside the scope of a general-purpose comparison tool.

The diff does not say why a change occurred either: it is a finding. To analyse a regression, this finding has to be cross-referenced with commits, deployments and request parameters.

JSON diff vs JSON Patch (RFC 6902)

A complementary format is JSON Patch (RFC 6902). It describes, as a list of operations (add, remove, replace, move, copy, test), how to transform one JSON document into another. Where our diff is a finding (human), JSON Patch is a recipe (machine). The two representations are equivalent for simple cases, and JSON Patch is useful for RESTful APIs that accept partial modifications.

Frequently asked questions

Does the diff depend on key order?

No: for a JSON object, order is not significant. The comparator produces the same result whether keys are sorted or not.

How do I handle arrays whose order does not matter?

The tool considers arrays as ordered by default (that is the JSON semantics). If you handle sets, sort both arrays by a natural key before comparing, or use a specialised comparison service that takes this semantics into account.

What is the difference with a Git diff?

Git compares lines of text. If the indentation or the key order differs, the Git diff is very verbose. The JSON diff works on the parsed structure and flags only data differences.

Is an invalid JSON accepted?

No: if one of the two JSON documents fails to parse, the tool returns an error. Validate first with our JSON validator.

Example request

curl -X POST https://cdrn.fr/api/v1/tools/json-diff/execute \
  -H "Content-Type: application/json" \
  -d '{"left":"...","right":"..."}'

Input schema

Field Type Required Default
left text
right text

Endpoints

  • GET https://cdrn.fr/api/v1/tools - lists every available tool
  • GET https://cdrn.fr/api/v1/tools/json-diff - returns the schema for this tool
  • POST https://cdrn.fr/api/v1/tools/json-diff/execute - runs this tool with a JSON payload