Free JSON Developer Tools
2026-02-23 · 10 min read · By AllJSONTools
Paste broken JSON and fix it instantly with AI — plain-English explanations included.
JSON has become the lingua franca of data exchange. APIs return it, configuration files are written in it, databases store it, and test fixtures depend on it. Wherever JSON travels, the need to compare two documents inevitably follows. Understanding what changed between two JSON payloads is a fundamental skill for modern software development.
API versioning. When you release a new version of an API, you need to know exactly which fields were added, removed, or modified. Diffing the response schemas or sample payloads between v1 and v2 gives you a clear migration guide and helps you write accurate changelogs.
Configuration drift detection. In distributed systems, configuration files can silently diverge across environments. Comparing the production config against staging reveals mismatches — a different database host, a missing feature flag, or an unexpected timeout value — before they cause incidents.
Debugging. When a bug report says "it worked yesterday," diffing yesterday’s API response against today’s can pinpoint the exact field that changed. This is faster than stepping through code line by line.
Testing. Snapshot tests, contract tests, and regression tests all rely on comparing expected JSON against actual JSON. A good diff algorithm tells you not just that something changed, but where and how.
Data migrations. When transforming data from one schema to another, diffing the input and output documents verifies that the migration script did what you intended and nothing was lost or corrupted in the process.
Not all changes are created equal. Before choosing a diff tool or algorithm, it helps to understand the categories of differences you might encounter between two JSON documents.
phone field was added to a user object."Alice" to "Bob"."42" to an integer 42. These are particularly dangerous because they can break deserialization logic.Different situations call for different diffing strategies. Here are the most common approaches, from simplest to most sophisticated.
A shallow diff compares only the top-level keys and values of two objects. If a value is a nested object, the algorithm checks reference equality (or serialized equality) rather than recursing into it. This is fast but misses changes buried inside nested structures. It is suitable for flat configuration objects or as a quick "did anything change at all?" check.
function shallowDiff(a, b) {
const changes = [];
const allKeys = new Set([...Object.keys(a), ...Object.keys(b)]);
for (const key of allKeys) {
if (!(key in a)) {
changes.push({ type: "added", key, value: b[key] });
} else if (!(key in b)) {
changes.push({ type: "removed", key, value: a[key] });
} else if (JSON.stringify(a[key]) !== JSON.stringify(b[key])) {
changes.push({ type: "changed", key, from: a[key], to: b[key] });
}
}
return changes;
}A deep diff walks the entire tree of both documents, recursing into nested objects and arrays. It produces a list of changes with full paths like user.address.city or items[2].price. This is the most common approach for general-purpose JSON comparison and is what most diff libraries implement. The trade-off is performance: deeply nested documents with large arrays can be expensive to compare.
function deepDiff(a, b, path = "") {
const changes = [];
if (typeof a !== typeof b) {
return [{ path: path || "/", type: "type_changed", from: a, to: b }];
}
if (a === null || b === null || typeof a !== "object") {
if (a !== b) {
return [{ path: path || "/", type: "changed", from: a, to: b }];
}
return [];
}
const allKeys = new Set([...Object.keys(a), ...Object.keys(b)]);
for (const key of allKeys) {
const newPath = path ? `${path}.${key}` : key;
if (!(key in a)) {
changes.push({ path: newPath, type: "added", value: b[key] });
} else if (!(key in b)) {
changes.push({ path: newPath, type: "removed", value: a[key] });
} else {
changes.push(...deepDiff(a[key], b[key], newPath));
}
}
return changes;
}A structural diff compares JSON documents purely by their tree structure. Two documents are different if any key, value, or nesting level does not match byte-for-byte. A semantic diff goes further: it understands that 1.0 and 1 may represent the same number, that key order in objects is insignificant, or that two arrays contain the same elements even if their order differs. The choice between structural and semantic diffing depends on your use case — strict API contract testing typically needs structural comparison, while data reconciliation benefits from semantic awareness.
JSON Patch is a standardized format (RFC 6902) for describing changes to a JSON document. Instead of showing a side-by-side diff, it produces an array of operations that, when applied sequentially, transform the original document into the new one. Each operation has an op field (add, remove, replace, move, copy, or test) and a path field using JSON Pointer syntax.
[
{ "op": "replace", "path": "/user/name", "value": "Bob" },
{ "op": "add", "path": "/user/phone", "value": "+1-555-0123" },
{ "op": "remove", "path": "/user/legacy_id" },
{ "op": "replace", "path": "/meta/version", "value": 2 }
]JSON Patch is particularly useful for PATCH endpoints in REST APIs, for transmitting minimal deltas over the network, and for building undo/redo systems. Because the format is standardized, patches generated by one library can be applied by another, regardless of programming language.
Let’s walk through a practical example. Suppose you have two versions of a user profile returned by an API. Here is the original response:
{
"id": 1001,
"name": "Alice Johnson",
"email": "alice@example.com",
"role": "editor",
"preferences": {
"theme": "light",
"notifications": true,
"language": "en"
},
"tags": ["premium", "early-adopter"]
}And here is the updated response after some changes were made:
{
"id": 1001,
"name": "Alice Johnson-Smith",
"email": "alice@example.com",
"role": "admin",
"preferences": {
"theme": "dark",
"notifications": true,
"language": "en",
"timezone": "America/New_York"
},
"tags": ["premium", "early-adopter", "beta-tester"],
"lastLogin": "2025-03-15T10:30:00Z"
}A deep diff of these two documents would produce the following change report:
[
{ "path": "name", "type": "changed", "from": "Alice Johnson", "to": "Alice Johnson-Smith" },
{ "path": "role", "type": "changed", "from": "editor", "to": "admin" },
{ "path": "preferences.theme", "type": "changed", "from": "light", "to": "dark" },
{ "path": "preferences.timezone", "type": "added", "value": "America/New_York" },
{ "path": "tags[2]", "type": "added", "value": "beta-tester" },
{ "path": "lastLogin", "type": "added", "value": "2025-03-15T10:30:00Z" }
]This output makes it immediately clear what changed: the user updated her name, was promoted to admin, switched to dark theme, a new timezone preference was added, a new tag was appended, and a lastLogin timestamp appeared. This kind of structured diff output is far more useful than a raw text diff, because it understands JSON semantics rather than treating the document as lines of text.
Real-world JSON comparison is rarely straightforward. Here are the edge cases that trip up most diff tools — and how to handle them.
Is [1, 2, 3] equal to [3, 2, 1]? It depends on context. If the array represents a ranked list (e.g., search results), order matters and these are different. If it represents a set of tags, order is irrelevant and they should be considered equal. Most diff tools default to order-sensitive comparison. If you need order-insensitive behavior, either sort both arrays before diffing or use a tool that supports set-based comparison modes.
// Order-insensitive array comparison
function arraysEqualUnordered(a, b) {
if (a.length !== b.length) return false;
const sorted_a = [...a].sort((x, y) => JSON.stringify(x).localeCompare(JSON.stringify(y)));
const sorted_b = [...b].sort((x, y) => JSON.stringify(x).localeCompare(JSON.stringify(y)));
return JSON.stringify(sorted_a) === JSON.stringify(sorted_b);
}JSON numbers are parsed into floating point values in most languages, which means 0.1 + 0.2 might not equal 0.3 exactly. When diffing financial data or scientific measurements, consider using an epsilon-based comparison (e.g., values within 0.0001 of each other are treated as equal) rather than strict equality. Alternatively, represent precise values as strings in your JSON to avoid floating point issues entirely.
In JSON, there is an important distinction between a key with a null value and a key that is absent entirely. The document {"name": null} is semantically different from {} — the first explicitly declares that name has no value, while the second says nothing about name at all. A good diff tool should distinguish between a key being removed and a key being set to null. Note that JavaScript’s undefined does not exist in JSON — it is silently dropped during serialization, which can cause unexpected "missing key" diffs.
Minified JSON and pretty-printed JSON are semantically identical, but a naive text-based diff (like diff or git diff) will flag every line as changed. Always parse JSON into objects before comparing, rather than diffing the raw text. This also eliminates false positives from insignificant differences like trailing whitespace or different indentation widths.
When diffing arrays of objects, how do you match items across the two arrays? Consider an array of users: if a user was deleted and a new one was added, a positional diff would report every subsequent item as "changed" because the indices shifted. A smarter approach is to match objects by a unique identifier (such as id) and then diff the matched pairs. This gives you accurate add/remove/update semantics rather than a cascade of false positives.
The right tool depends on your workflow. Here is how the most common approaches compare:
| Tool / Approach | Best For | Handles Nesting | Visual Output | Automation |
|---|---|---|---|---|
| Manual inspection | Very small documents | No — error-prone | N/A | None |
jq (CLI) | Quick terminal checks | Via scripting | Text-based | Good (scriptable) |
| AllJSONTools Diff | Visual comparison in the browser | Yes — deep recursive | Side-by-side with highlights | Paste and go |
Programmatic (deep-equal, deep-diff) | CI/CD pipelines, test suites | Yes — full tree traversal | JSON change reports | Excellent (library-based) |
For quick one-off comparisons, a visual tool like AllJSONTools’s JSON Diff is the fastest path to answers. For automated testing and CI pipelines, a programmatic library gives you fine-grained control over comparison logic, thresholds, and output formatting.
Snapshot tests capture the output of a function or component and save it as a JSON file. On subsequent runs, the test framework diffs the new output against the stored snapshot. If anything changed, the test fails and shows you exactly what differs. This pattern is popular in frontend testing (Jest snapshots) and API testing alike.
// Jest snapshot test for an API response
test("GET /api/users/1 returns expected shape", async () => {
const response = await fetch("/api/users/1");
const data = await response.json();
// Jest will deep-diff 'data' against the stored snapshot
expect(data).toMatchSnapshot();
});When a snapshot test fails, the diff output tells you whether the change is intentional (update the snapshot) or a regression (fix the code). The quality of this workflow depends entirely on the quality of the underlying diff algorithm.
Contract tests verify that an API produces responses matching an agreed-upon structure. Rather than checking every value, they focus on the shape: are all expected keys present? Are the types correct? Has any required field been removed? By diffing the actual response against a reference document, you catch breaking changes before they reach consumers.
// Contract test: diff actual response against reference
const reference = {
id: expect.any(Number),
name: expect.any(String),
email: expect.stringMatching(/@/),
role: expect.stringMatching(/^(user|admin|editor)$/),
createdAt: expect.any(String)
};
test("user endpoint matches contract", async () => {
const response = await fetch("/api/users/1");
const data = await response.json();
expect(data).toMatchObject(reference);
});Beyond snapshots and contracts, JSON diffing is invaluable for regression detection in data pipelines. If your ETL process transforms input data into an output document, you can diff the output against a known-good baseline after every code change. Any unexpected differences indicate a potential regression. Combining this with a CI pipeline means regressions are caught automatically on every pull request, long before they reach production.
Understanding diff algorithms is valuable, but sometimes you just need to paste two JSON documents and see what changed. Our free JSON Diff tool does exactly that — paste your original JSON on the left, your updated JSON on the right, and get an instant, color-coded comparison with full support for nested objects and arrays.
The tool runs entirely in your browser, so your data never leaves your machine. It highlights added keys in green, removed keys in red, and changed values with clear before/after labels. Whether you are debugging an API response, reviewing a configuration change, or validating a data migration, it gives you the answers you need in seconds.
For programmatic use in your own projects, consider libraries like deep-diff for Node.js, jsondiff for Python, or go-jsondiff for Go. If you need a standards-compliant approach, implement JSON Patch (RFC 6902) using libraries such as fast-json-patch in JavaScript or jsonpatch in Python. These tools integrate seamlessly into test suites, CI pipelines, and monitoring systems.
JSON comparison is one of those skills that pays dividends across every area of software development. Whether you choose a visual tool, a CLI utility, or a programmatic library, the key is to move beyond naive text-based diffs and embrace tools that understand JSON structure. Your debugging sessions, test suites, and deployment pipelines will thank you.
Paste broken JSON and fix it instantly with AI — plain-English explanations included.
Learn what JSON Schema is, how it works, and how to use it for API validation, form generation, and data documentation. Includes examples and common patterns.
Learn how to safely parse, validate, and handle JSON API responses in production. Covers Zod, JSON Schema, error handling strategies, and type-safe clients.
Everything you need to know about parsing JSON in JavaScript — JSON.parse, JSON.stringify, error handling, reviver functions, fetch API, TypeScript type safety with Zod, streaming large files, and common pitfalls. Includes AI-powered error fixing.