Comparing two JSON documents sounds simple until a text diff marks every line as changed because one file uses tabs, or because a server returned the same keys in a different order. This guide shows how to get a clean, meaningful comparison and how to read the result.
Text diff vs structural diff
There are two ways to compare JSON:
- Text diff compares the documents line by line, like
git diff. It is sensitive to whitespace, indentation and key order, so the output depends on how each document was formatted.
- Structural (semantic) diff parses both documents and compares the data: which keys were added, removed or changed, and which array items differ. Formatting is ignored completely.
For reviewing configuration changes, a text diff of consistently formatted files works well. For comparing API responses, a structural diff is usually more useful.
Compare two JSON documents in the browser
- Open the JSON Formatter and paste the first document into the left editor and the second into the right.
- Click Compare in the header. The view highlights added, removed and changed lines side by side.
- If you see changes on almost every line, format and sort both sides first (next section), then compare again.
Both documents stay in your browser, so it's safe to compare responses from internal or production systems.
Remove noise before comparing
- Validate both inputs. A diff of invalid JSON isn't meaningful. Fix syntax errors first with Validate JSON.
- Format both the same way. Use the same indent size for both documents so whitespace differences disappear; see How to pretty print JSON.
- Sort keys. Objects are unordered, so
{"a":1,"b":2} and {"b":2,"a":1} are the same data. Sorting both sides makes them identical as text; see Sort JSON keys.
- Remove volatile fields. Timestamps, request IDs, trace IDs and nonces change on every call. Delete them or replace them with a fixed placeholder before comparing, or the diff will always show changes.
Reading the result
- Changed value: the same key has a different value, for example
"status": "active" became "status": "suspended". This is usually the change you care about.
- Added or removed key: a field appears on only one side. In API responses, this can mean a new version, a feature flag, or a field that's omitted when
null.
- Type change:
"id": 42 vs "id": "42". These look nearly identical but break strict clients, so treat them as real differences.
- Array changes: if one item is inserted at the start of an array, a naive comparison reports every following item as changed. When array items have IDs, compare by ID rather than by position.
Comparing on the command line
To compare two API responses with jq and diff, normalize both (sorted keys, consistent formatting) and diff the results:
bash
diff <(jq -S . before.json) <(jq -S . after.json)
To ignore a volatile field, delete it in the same step:
bash
diff <(jq -S 'del(.meta.requestId)' before.json) \
<(jq -S 'del(.meta.requestId)' after.json)
Common use cases
- Regression testing: compare a response from staging with the same request in production.
- Reviewing config changes: see exactly which settings differ between environments.
- Debugging integrations: compare the payload you sent with an example from the API documentation to spot a missing or misspelled field.
- Data migrations: check that records were transformed as expected.
If one of the documents is very large, see Handle large JSON for performance tips.