X Xerobit

JSON Patch (RFC 6902) — Operation-Based JSON Document Updates

JSON Patch (RFC 6902) defines a sequence of operations (add, remove, replace, move, copy, test) to modify JSON documents. Here's the full operation reference with examples, and...

Mian Ali Khalid · · 5 min read
Use the tool
JSON Diff
Compare two JSON objects structurally with field-by-field diff.
Open JSON Diff →

JSON Patch (RFC 6902) describes changes to a JSON document as a sequence of operations. Each operation specifies a JSON Pointer path and what to do at that path: add, remove, replace, move, copy, or test.

Use the JSON Diff Tool to compare JSON documents and generate diffs.

JSON Patch document format

A JSON Patch document is a JSON array of operation objects:

[
  { "op": "replace", "path": "/title", "value": "New Title" },
  { "op": "remove",  "path": "/draft" },
  { "op": "add",     "path": "/tags/-", "value": "featured" }
]

Each operation has:

  • op — the operation type
  • path — a JSON Pointer (RFC 6901) to the target location
  • value — the value to use (not needed for remove and move)
  • from — source path (for move and copy)

JSON Pointer paths

JSON Pointer (RFC 6901) uses / to navigate document structure:

{
  "user": {
    "name": "Alice",
    "address": {
      "city": "London"
    }
  },
  "tags": ["a", "b", "c"]
}
PathPoints to
/userThe user object
/user/name"Alice"
/user/address/city"London"
/tags/0"a" (first array element)
/tags/-End of tags array (for append)
“ (empty)Root document

Escape ~ as ~0 and / as ~1 in key names:

{ "op": "add", "path": "/a~1b", "value": 1 }
// Adds key "a/b" to the root

Operations reference

add

Adds a value at the target path. For arrays, inserts at the index:

[
  { "op": "add", "path": "/name", "value": "Alice" },
  { "op": "add", "path": "/tags/0", "value": "new" },
  { "op": "add", "path": "/tags/-", "value": "appended" }
]
  • /tags/0 — inserts at index 0, shifting existing elements
  • /tags/- — appends to end of array

remove

Removes the value at the target path:

[
  { "op": "remove", "path": "/draft" },
  { "op": "remove", "path": "/tags/1" }
]

replace

Replaces the value at the target path. The path must exist:

[
  { "op": "replace", "path": "/title", "value": "Updated Title" },
  { "op": "replace", "path": "/user/name", "value": "Bob" }
]

move

Removes the value at from and adds it at path:

[
  { "op": "move", "from": "/old/location", "path": "/new/location" }
]

Useful for renaming keys or restructuring:

[
  { "op": "move", "from": "/firstName", "path": "/first_name" }
]

copy

Copies the value at from to path (original remains):

[
  { "op": "copy", "from": "/user/email", "path": "/contactEmail" }
]

test

Verifies a value at a path. If the test fails, the entire patch operation is aborted:

[
  { "op": "test",    "path": "/status", "value": "draft" },
  { "op": "replace", "path": "/status", "value": "published" }
]

The test operation makes JSON Patch atomic — if any operation fails, none are applied.

Full example

Original document:

{
  "id": 1,
  "title": "Draft Post",
  "author": { "name": "Alice", "email": "alice@example.com" },
  "tags": ["tech", "draft"],
  "status": "draft",
  "views": 0
}

JSON Patch:

[
  { "op": "test",    "path": "/status",       "value": "draft" },
  { "op": "replace", "path": "/title",        "value": "Published Post" },
  { "op": "replace", "path": "/status",       "value": "published" },
  { "op": "remove",  "path": "/tags/1" },
  { "op": "add",     "path": "/tags/-",       "value": "published" },
  { "op": "add",     "path": "/publishedAt",  "value": "2026-05-11" }
]

Result:

{
  "id": 1,
  "title": "Published Post",
  "author": { "name": "Alice", "email": "alice@example.com" },
  "tags": ["tech", "published"],
  "status": "published",
  "views": 0,
  "publishedAt": "2026-05-11"
}

Implementing JSON Patch

JavaScript with fast-json-patch

import { applyPatch, compare, validate } from 'fast-json-patch';

const original = { a: 1, b: 2, c: { d: 3 } };
const patch = [
  { op: 'replace', path: '/a', value: 10 },
  { op: 'remove',  path: '/b' },
  { op: 'add',     path: '/e', value: 5 },
];

// Validate the patch first:
const errors = validate(patch, original);
if (errors.length > 0) {
  console.error('Invalid patch:', errors);
}

// Apply:
const result = applyPatch(original, patch).newDocument;
// { a: 10, c: { d: 3 }, e: 5 }

// Generate patch from diff:
const target = { a: 10, c: { d: 3 }, e: 5 };
const generated = compare(original, target);
// [{ op: 'replace', path: '/a', value: 10 }, ...]

Python with jsonpatch

import jsonpatch

original = {"a": 1, "b": 2, "c": {"d": 3}}
patch = jsonpatch.JsonPatch([
    {"op": "replace", "path": "/a", "value": 10},
    {"op": "remove",  "path": "/b"},
    {"op": "add",     "path": "/e", "value": 5},
])

result = patch.apply(original)
# {"a": 10, "c": {"d": 3}, "e": 5}

# Generate patch from diff:
target = {"a": 10, "c": {"d": 3}, "e": 5}
generated = jsonpatch.make_patch(original, target)
print(generated.to_string())

HTTP PATCH with JSON Patch

PATCH /articles/123 HTTP/1.1
Content-Type: application/json-patch+json

[
  { "op": "replace", "path": "/title", "value": "New Title" },
  { "op": "add",     "path": "/tags/-", "value": "featured" }
]

Express.js handler:

import { applyPatch } from 'fast-json-patch';

app.patch('/articles/:id', async (req, res) => {
  const patch = req.body;  // JSON Patch array
  const article = await db.articles.findById(req.params.id);
  
  try {
    const { newDocument } = applyPatch(article, patch);
    await db.articles.update(req.params.id, newDocument);
    res.json(newDocument);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

JSON Patch vs JSON Merge Patch

AspectJSON PatchJSON Merge Patch
FormatArray of operationsJSON object (partial update)
Atomic (test operation)YesNo
Array element operationsYes (by index)No (replace entire array)
Nested key updatesYes (by path)Replaces parent object
ComplexityHigherSimpler
Best forComplex mutationsSimple field updates

Related posts

Related tool

JSON Diff

Compare two JSON objects structurally with field-by-field diff.

Written by Mian Ali Khalid. Part of the Data & Format pillar.