N

Runs in your browser · nothing is uploaded

JSON Diff & YAML Compare

A JSON diff by structure: paste or open two JSON or YAML documents to see every added, removed and changed value by path — not by line — then merge them or export the difference as a JSON Patch.

Paste, drop a file here or open one. It's read in your browser and never uploaded.

Read as JSON

Paste, drop a file here or open one. It's read in your browser and never uploaded.

Read as YAML

Comparison options

Comparison options

Key order is always ignored, and 1 and 1.0 are always the same number.

Used when array order is ignored. Leave empty to match whole values only.

JSONPath ($.a.b[0]), JSON Pointer (/a/b/0) or a.b.0; * matches any key or index.

Result

8 differences: 2 added, 2 removed, 3 changed, 1 type changed

Show change kinds
Differences between the left and right documents
ChangePathLeftRight
Changed$.version"1.4.0""1.5.0"
Type changed$.replicas2"3"
Removed$.debugtrue—
Changed$.env.LOG_LEVEL"info""debug"
Added$.env.TIMEOUT_MS—3000
Changed$.ports[1]90909443
Added$.users[0]—{"id":2,"name":"Ben","role":"admin"}
Removed$.users[1]{"id":2,"name":"Ben","role":"ops"}—

Structural diff vs text diff

The same data, reordered

Left

{
  "name": "api",
  "port": 80,
  "tags": [
    "web",
    "eu"
  ],
  "db": {
    "host": "db1",
    "pool": 5
  }
}

Right

{
  "db": {
    "pool": 5,
    "host": "db2"
  },
  "tags": [
    "web",
    "eu",
    "beta"
  ],
  "port": "80",
  "name": "api"
}

Compared line by line, 11 lines differ, because the keys moved. Compared as data, there are 3 changes:

What the structural diff reports

ChangeJSONPathPointerLeft → right
Type changed$.port/port80 → "80"
Added$.tags[2]/tags/2— → "beta"
Changed$.db.host/db/host"db1" → "db2"

"Type changed" means the value is now a different kind of thing — here the number 80 became the string "80", which many config loaders treat differently. The tags array gained one item at the end, so only that item is reported.

As a JSON Patch (RFC 6902)

[
  {
    "op": "replace",
    "path": "/port",
    "value": "80"
  },
  {
    "op": "add",
    "path": "/tags/2",
    "value": "beta"
  },
  {
    "op": "replace",
    "path": "/db/host",
    "value": "db2"
  }
]

Merging two documents

  • ObjectsMerged key by key. A key on only one side is kept; left keys come first, then keys only on the right.
  • ConflictsTwo different values at the same path (or a number on one side and an object on the other). Prefer right, prefer left, or choose each one.
  • ArraysReplace (a conflict if they differ), concatenate, union by value (right items not already on the left are added), or merge by a key field such as "id".

Worked example

Merging the left document above with {"db":{"host":"db2","ssl":true},"tags":["eu","beta"],"port":8080}, preferring the right side and taking the union of arrays:

{
  "name": "api",
  "port": 8080,
  "tags": [
    "web",
    "eu",
    "beta"
  ],
  "db": {
    "host": "db2",
    "pool": 5,
    "ssl": true
  }
}

2 conflicts ($.port, $.db.host) went to the right side; db.pool and name came from the left only, db.ssl from the right only.

YAML is read with the YAML 1.2 core schema, so values like yes, no and on stay strings, and duplicate keys are reported as errors. Comments, anchors and tags aren't carried into the merged output.

Sources: RFC 6902 (JavaScript Object Notation (JSON) Patch) and RFC 6901 (JSON Pointer), IETF; YAML 1.2.2 specification. Checked 14 October 2026.

Frequently asked questions

What's the difference between a structural diff and a text diff?+

A text diff compares lines. A structural diff parses both documents and compares the data. In the example below, 11 lines differ as text because the keys were reordered, but there are only 3 real changes: $.port type changed, $.tags[2] added, $.db.host changed.

Does key order matter?+

No. JSON objects and YAML mappings are unordered, so {"a": 1, "b": 2} and {"b": 2, "a": 1} give 0 differences. Whitespace, indentation and quote style don't matter either, and 1 and 1.0 are the same number (0 differences).

How are arrays compared?+

By position, by default, but unchanged items are lined up first, so inserting one item shows as one addition rather than every later item changing. [1, 2, 3] and [3, 2, 1] give 4 differences in order and 0 with "Ignore array order". With the key field set to "id", objects are matched by id wherever they sit: two reordered users with one new role give 1 change ($[1].role).

Can I compare JSON with YAML?+

Yes. Each side is detected separately (or set by hand), parsed to plain data and then compared, so a JSON file and its YAML version with the same data show no differences. Parse errors show the line and column.

What is the JSON Patch export?+

It's an RFC 6902 patch: a list of add, remove and replace operations that turns the left document into the right one. The example below needs 3 operations. The tool applies the patch to the left document and checks the result equals the right before you copy it. The patch ignores the comparison options, because it has to reproduce the right document exactly.

How does merging work?+

Objects are merged key by key, and keys that exist on only one side are kept. When both sides have different values at the same path, that's a conflict: prefer right, prefer left, or pick a side for each conflict. Arrays can be replaced (a conflict if they differ), concatenated, combined as a union of values, or merged object by object using a key field.

Are YAML comments and anchors kept when I merge?+

No. Both inputs are read as plain data first, so comments, anchors, aliases and custom tags are lost; aliases and merge keys are expanded into their values. For example, a prod entry that merges a &base anchor comes out as {"base":{"retries":3},"prod":{"retries":3,"region":"eu"}}.

Can I ignore fields like timestamps or IDs?+

Yes. List paths under “Ignore these paths”, one per line, as JSONPath ($.meta.updated), JSON Pointer (/meta/updated) or a dot path (meta.updated); * matches any key or array index, and everything under an ignored path is skipped. Two orders that differ only in a timestamp give 1 change, and 0 with /items/*/timestamp ignored.

Is the number 80 the same as the string "80"?+

Not by default: a number and a string are different types, so in the example below port shows as type changed. Tick “Treat "1.0" and 1 as equal” and strings holding a number are compared as numbers, so port no longer counts as a change. Handy when one file comes from a system that quotes everything.

What's the difference between JSONPath and JSON Pointer?+

Both name a place in a document. JSONPath starts with $ and uses dots and brackets, such as $.db.host or $.tags[2]; JSON Pointer (RFC 6901) uses slashes, such as /db/host or /tags/2, and is what JSON Patch uses. In a pointer, / inside a key is written ~1 and ~ is ~0, so the key "a/b" becomes /a~1b/x. Switch the change list between the two with “Path style”.

Is there a size limit?+

There's no hard limit, but documents over 5 million characters show a warning: they're processed in your browser and can be slow. The line view stops at 5,000 lines per side and the change list at 500 rows; the copied list and the JSON Patch cover everything.

Is my data uploaded?+

No. Files are read and compared in your browser. Nothing is sent to a server or stored.