Skip to content
Data2026-05-296 min read

Online JSON Diff Tool: Compare and Analyze JSON Data Differences

What Is JSON Diff

JSON Diff compares two JSON data structures and identifies differences. It detects additions, deletions, and modifications between two JSON objects. Drop two payloads into our JSON Diff tool to highlight the changes side by side.

Comparison Example

Original JSON:

{
  "name": "Alice",
  "age": 28,
  "hobbies": ["reading", "gaming"]
}

Modified JSON:

{
  "name": "Alice",
  "age": 29,
  "hobbies": ["reading", "coding"],
  "email": "alice@example.com"
}

Diff Result:

{
  "age": { "old": 28, "new": 29 },
  "hobbies[1]": { "old": "gaming", "new": "coding" },
  "email": { "added": "alice@example.com" }
}

Why You Need JSON Diff

  1. API response validation: Compare API returns with expected values (the online JSON diff pastes-and-compares with four granularity levels)
  2. Config change detection: Compare configuration file modifications
  3. Data migration verification: Confirm data migration correctness
  4. Code review: Compare JSON output between two versions
  5. Automated testing: Assert data changes in tests
  6. Version control: Track JSON data change history

Diff Result Types

Change TypeDescriptionMarker
AddedKey doesn't exist in original+ or added
DeletedKey exists in original but not modified- or deleted
ChangedKey exists but values differ~ or changed
UnchangedKey and value are the sameNo marker

How to Use an Online Tool

Using ToolVault's JSON Diff Tool:

  1. Enter original JSON on the left
  2. Enter modified JSON on the right
  3. The tool auto-compares and highlights differences
  4. Shows specific additions, deletions, and changes
  5. Copy the diff list, or copy an RFC 6902 JSON Patch with one click

Noise-free comparison: ignore array order and ignore keys

When diffing API responses or logs, the fields you actually care about get buried under two kinds of noise: order-insignificant arrays (tags, permission lists) and metadata fields that change on every write (updatedAt, traceId). The tool panel offers three options:

  • Ignore array order: arrays match as multisets — [1,2,3] and [3,1,2] are identical; leftover elements pair up by minimal difference, reported as modifications instead of "whole row removed + whole row added".
  • Array key (e.g. id): combined with ignore-order, object arrays align on a business key. Rows with the same id report field-level diffs like users[id=7].name even when they moved position.
  • Ignore keys: comma-separated field names applied at any depth, e.g. updatedAt, traceId — skipped entirely, leaving only signal in the diff list.

The judgement call is unchanged: do not enable "ignore array order" for order-sensitive APIs (timelines, leaderboards). When in doubt, run the default positional mode first.

Exporting JSON Patch (RFC 6902)

A diff list is for humans; machines (CI assertions, change replay) consume JSON Patch. Click "Copy JSON Patch" to get a standard sequence of add / remove / replace operations with JSON Pointer paths (e.g. /config/timeout). Two boundaries to know:

  • With "ignore array order" enabled, array paths are logical positions, not indices — they cannot map to executable patches, so the patch button hides in that mode. Use the diff list instead.
  • Big integers (like snowflake IDs) keep their exact text form inside the patch output; but any implementation that consumes the patch via JSON.parse still limits numbers to IEEE 754 doubles — that is a boundary of the patch protocol itself, not of this tool.

JSON Diff in Code

JavaScript

// Deep compare two objects
function deepDiff(oldObj, newObj, path = '') {
  const diffs = {};
  const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);

  for (const key of allKeys) {
    const currentPath = path ? `${path}.${key}` : key;

    if (!(key in oldObj)) {
      diffs[currentPath] = { type: 'added', value: newObj[key] };
    } else if (!(key in newObj)) {
      diffs[currentPath] = { type: 'deleted', value: oldObj[key] };
    } else if (typeof oldObj[key] === 'object' && typeof newObj[key] === 'object') {
      Object.assign(diffs, deepDiff(oldObj[key], newObj[key], currentPath));
    } else if (oldObj[key] !== newObj[key]) {
      diffs[currentPath] = { type: 'changed', old: oldObj[key], new: newObj[key] };
    }
  }

  return diffs;
}

Python

def deep_diff(old, new, path=''):
    diffs = {}
    all_keys = set(list(old.keys()) + list(new.keys()))

    for key in all_keys:
        current_path = f"{path}.{key}" if path else key

        if key not in old:
            diffs[current_path] = {'type': 'added', 'value': new[key]}
        elif key not in new:
            diffs[current_path] = {'type': 'deleted', 'value': old[key]}
        elif isinstance(old[key], dict) and isinstance(new[key], dict):
            diffs.update(deep_diff(old[key], new[key], current_path))
        elif old[key] != new[key]:
            diffs[current_path] = {'type': 'changed', 'old': old[key], 'new': new[key]}

    return diffs

Structural diff vs textual diff: when line diff lies about JSON

A one-line JSON (minified) has no lines for a line-diff to work with — it reports "everything changed". A pretty-printed reordering (same object, keys alphabetized by a different serializer) produces a thousand-line textual diff with zero semantic change. The fix is structural: parse both sides, compare trees, report paths — order-insensitive for object keys (per JSON spec), order-sensitive for arrays (per semantics). Our JSON diff does the structural pass; the discipline it encodes is that textual diff is the wrong tool for machine-generated JSON. Reserve line-diff for hand-edited files where line context has meaning.

Array diffing: the alignment problem

Arrays are diffed positionally by naive tools: element 5 deleted shifts every subsequent element, reported as N changes when one insertion occurred. Smarter array diffs (LCS-based, like the Myers algorithm text diff applied to serialized elements) align by content and report the single insertion. The trade: LCS on large arrays of objects is expensive, and "similar but not equal" elements (same id, changed fields) defeat naive alignment — the production-grade answer keys arrays by id-field when the schema has one, treating the array as a map for diff purposes. If your diff tool shows massive array churn on small changes, it lacks key-based alignment; check with an id-keyed sample.

Normalizing before diffing: the etiquette of stable comparisons

Machine-written JSON varies by serializer: key order, number formatting (1.0 vs 1), unicode escapes (\u0041 vs A), insignificant whitespace. Normalization — canonical serialization (sorted keys, standardized number format, no whitespace) before diffing — removes this entire noise class. RFC 8785 (JSON Canonicalization Scheme) is the formal spec; a pragmatic subset (sort keys, normalize numbers) captures 95% of the benefit. Diff tools that normalize first report signal; tools that diff raw bytes report serializer quirks. When diffs feed automated pipelines (release notes, change detection), normalization is not optional — the pipeline fires on every serializer upgrade otherwise.

FAQ

Can JSON Diff Handle Large Files?

The tool runs a full recursive comparison locally in the browser: configs and responses of a few MB compare in seconds. For files beyond ~10MB, first trim irrelevant subtrees with "ignore keys", or extract the paths you care about with jq before comparing. The leftover-element pairing in "ignore array order" mode is an O(n²) greedy pass — unordered arrays with thousands of elements will feel slow; filling in the "array key" when elements have a business key cuts that cost substantially.

Can Diff Results Be Merged?

Yes. Click "Copy JSON Patch" to get an RFC 6902 patch (add / remove / replace) that libraries like fast-json-patch can apply back onto the original JSON. Note that in "ignore array order" mode the paths carry no index semantics, so patch export is unavailable there.

How to Handle Array Order Changes?

Array diffing has two strategies: positional comparison (default — strict but order-sensitive) and content-based comparison (enable "ignore array order" — order-insensitive but positions are lost). When elements are objects with an id, also fill in the "array key" to align on the business key, giving you both order-insensitivity and field-level precision.

Implementation notes

Building this tool hit a big-integer pitfall: parsing must run in a lossless mode (raw numeric text preserved), and equal-value big integers must compare by that raw text — compare by instance reference of the parsed output instead, and two large IDs with identical values get reported as modified, a pure phantom diff.


From the ToolVault developer notebook. Browse more online tools on the homepage.