JSON Patch vs JSON Merge Patch: RFC 6902 vs RFC 7396
Two standard ways to send just the changes to a JSON document — how each works, the gotchas (arrays, null), and which to reach for.
When a client wants to update one field of a resource, sending the entire object back is wasteful and race-prone. Two IETF standards let you send only the change instead: JSON Patch (RFC 6902) and JSON Merge Patch (RFC 7396). They solve the same problem in very different ways, and picking the wrong one leads to surprises — like an array you meant to tweak getting wiped, or a field you can't set to null. Here's how each works and when to use it.
A shared starting document
Every example below patches this object:
{
"name": "Ada",
"age": 36,
"tags": ["admin", "beta"],
"address": { "city": "London", "zip": "EC1" }
}
JSON Merge Patch (RFC 7396): looks like the target
A merge patch is a partial copy of the document. The rules are simple: a key that's present is set (recursively, for objects); a key whose value is null is deleted; a key that's absent is left untouched. To rename the city, drop the age, and add a tag set:
{
"age": null,
"address": { "city": "Berlin" }
}
Result: age is removed, address.city becomes "Berlin" (and address.zip is kept, because objects merge), while name and tags are unchanged. That readability is the appeal — but it has two sharp edges:
- You can't set a value to
null, becausenullmeans “delete.” - Arrays are replaced wholesale. Sending
"tags": ["admin"]overwrites the entire array — there's no way to add or remove a single element.
JSON Patch (RFC 6902): a list of operations
A JSON Patch is an ordered array of operations, each with an op and a path (a JSON Pointer). The same edits, plus a precise array change:
[
{ "op": "remove", "path": "/age" },
{ "op": "replace", "path": "/address/city", "value": "Berlin" },
{ "op": "add", "path": "/tags/-", "value": "early-access" }
]
The six operations are add, remove, replace, move, copy, and test. The /tags/- path appends to an array; /tags/0 would target the first element. test asserts a value before applying (useful for optimistic concurrency — the patch fails if the document isn't what you expected). Operations apply in order and are meant to be atomic: if one fails, none should take effect.
Side-by-side: which to choose
| JSON Merge Patch (7396) | JSON Patch (6902) | |
|---|---|---|
| Shape | Partial document that mirrors the target | Array of explicit operations |
| Delete a field | Set it to null | { "op": "remove", "path": "…" } |
| Set a value to null | Not possible | Yes — replace with null |
| Array elements | Whole array replaced | Add / remove / replace by index |
| Preconditions | None | test op (optimistic concurrency) |
| Readability | High — looks like the data | Lower — verbose op list |
| Media type | application/merge-patch+json | application/json-patch+json |
Rule of thumb: reach for Merge Patch when you're setting a handful of object fields and never need element-level array edits or literal nulls — it's the friendlier default for most PATCH APIs. Reach for JSON Patch when you need precise array operations, move/copy, conditional test, or guaranteed ordering.
Applying patches in code
In JavaScript, fast-json-patch handles RFC 6902, and there are small libraries for 7396:
import { applyPatch } from "fast-json-patch";
const patch = [{ op: "replace", path: "/address/city", value: "Berlin" }];
const updated = applyPatch(doc, patch).newDocument;
In Python, use jsonpatch for 6902 and json-merge-patch for 7396:
import jsonpatch
patch = jsonpatch.JsonPatch([
{"op": "replace", "path": "/address/city", "value": "Berlin"}
])
updated = patch.apply(doc)
Apply patches without code
When I'm working out a patch — or checking what an API will do before sending it — I test it in the browser first. Our free tools apply each spec live and client-side (disclosure: I built them): the JSON Patch tool applies RFC 6902 operations, and the JSON Merge Patch tool applies RFC 7396. To see what actually changed between two versions of a document, the JSON Compare tool gives a semantic diff.
FAQs
What's the difference between JSON Patch and JSON Merge Patch?
JSON Patch (6902) is an ordered array of operations (add/remove/replace/move/copy/test). JSON Merge Patch (7396) is a partial document where present keys are set and null deletes. Patch is precise; Merge Patch is simpler.
When should I use JSON Merge Patch?
For simple field updates where you don't need element-level array operations or to store a literal null.
How do I delete a field with JSON Merge Patch?
Set it to null — RFC 7396 treats null as “remove this key.”
Can JSON Merge Patch modify a single array element?
No — it replaces the whole array. Use JSON Patch to target an index like /items/2.
What content types do they use?application/json-patch+json for 6902 and application/merge-patch+json for 7396, both with HTTP PATCH.