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...
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 typepath— a JSON Pointer (RFC 6901) to the target locationvalue— the value to use (not needed forremoveandmove)from— source path (formoveandcopy)
JSON Pointer paths
JSON Pointer (RFC 6901) uses / to navigate document structure:
{
"user": {
"name": "Alice",
"address": {
"city": "London"
}
},
"tags": ["a", "b", "c"]
}
| Path | Points to |
|---|---|
/user | The 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
| Aspect | JSON Patch | JSON Merge Patch |
|---|---|---|
| Format | Array of operations | JSON object (partial update) |
| Atomic (test operation) | Yes | No |
| Array element operations | Yes (by index) | No (replace entire array) |
| Nested key updates | Yes (by path) | Replaces parent object |
| Complexity | Higher | Simpler |
| Best for | Complex mutations | Simple field updates |
Related tools
- JSON Diff Tool — compare JSON documents visually
- JSON Merge Patch — simpler partial updates (RFC 7396)
- Comparing JSON Structurally — diff approaches
Related posts
- Comparing JSON Structurally (Not Just as Strings) — Two JSON documents can be byte-different and semantically identical. Or byte-ide…
- How to Compare JSON Objects — Deep Equality and Diff in JavaScript and Python — Comparing JSON objects with == won't work for deep equality. Here's how to deep-…
- Detecting Changes in JSON Data — Audit Logs, Diffs, and Change Tracking — Detecting what changed in a JSON document is essential for audit logs, versionin…
- JSON Diff Tool — Compare Two JSON Objects and Find Differences — A JSON diff tool compares two JSON structures semantically, not textually. It fi…
- JSON Merge Patch — Partial Updates to JSON Documents (RFC 7396) — JSON Merge Patch (RFC 7396) is a simple format for partial JSON updates. A null …
Related tool
Compare two JSON objects structurally with field-by-field diff.
Written by Mian Ali Khalid. Part of the Data & Format pillar.