← All articles

JSON Patch vs JSON Merge Patch: RFC 6902 vs 7396

JSON Patch (RFC 6902) sends explicit operations; JSON Merge Patch (RFC 7396) overlays a partial object. Compare both with examples and pick the right one.

When an HTTP API needs to update part of a resource, two IETF standards compete for the job: JSON Merge Patch (RFC 7396) and JSON Patch (RFC 6902). They look similar but work very differently — Merge Patch overlays a partial object, while JSON Patch sends an explicit list of operations. This guide shows how each works, compares them head to head, and helps you pick the right one.

The Problem: Partial Updates

A PUT request replaces an entire resource, which is wasteful and risky when you only want to change one field. The HTTP PATCH method exists for partial updates — but PATCH doesn't define a body format. That's what these two standards provide.

JSON Merge Patch (RFC 7396)

A Merge Patch is just a partial version of the target document. The server overlays it: keys in the patch are set, keys set to null are deleted, and keys not mentioned are left alone.

// Original
{ "title": "Hello", "author": "Ada", "tags": ["a", "b"], "draft": true }

// Merge Patch body (Content-Type: application/merge-patch+json)
{ "title": "Hello World", "draft": null }

// Result
{ "title": "Hello World", "author": "Ada", "tags": ["a", "b"] }
//   ^ title updated        ^ author untouched       ^ draft deleted (was null)

It's intuitive and compact. The catch: because null means "delete," you cannot use Merge Patch to set a value to null, and arrays can only be replaced wholesale — there's no way to change a single array element.

JSON Patch (RFC 6902)

A JSON Patch is an ordered array of operations, each targeting a location with a JSON Pointer path. It's explicit and precise:

// JSON Patch body (Content-Type: application/json-patch+json)
[
  { "op": "replace", "path": "/title", "value": "Hello World" },
  { "op": "remove",  "path": "/draft" },
  { "op": "add",     "path": "/tags/-", "value": "c" },
  { "op": "test",    "path": "/author", "value": "Ada" }
]

The six operations:

opEffect
addAdd a value (or append to an array with /-)
removeDelete the value at a path
replaceReplace the value at a path
moveMove a value from one path to another
copyCopy a value to another path
testAssert a value (abort the whole patch if it fails)

The test op enables safe, atomic updates: if the document isn't in the expected state, the entire patch is rejected — useful for optimistic concurrency control.

Head-to-Head Comparison

JSON Merge PatchJSON Patch
RFC73966902
Content-Typeapplication/merge-patch+jsonapplication/json-patch+json
ReadabilityHigh — looks like the dataLower — list of operations
Can set a value to nullNo (null means delete)Yes
Modify a single array elementNo (replace whole array)Yes (by index)
Conditional / atomic updatesNoYes (test op)
Move / copyNoYes
Best forSimple object field updatesPrecise, array-aware, atomic edits

When to Use Which

  • JSON Merge Patch — when clients mostly update top-level object fields and you value a body that reads like the resource. Great for simple settings and profile updates. Just remember you can't set fields to null or edit array items.
  • JSON Patch — when you need to edit array elements, move or copy values, set fields to null, or apply changes atomically with a precondition. The standard choice for collaborative editing and audit-friendly change sets.

HTTP PATCH Semantics: Idempotency and Headers

Two HTTP details that often catch teams shipping a PATCH endpoint:

  • PATCH is not required to be idempotent (unlike PUT). A JSON Patch with {"op":"add","path":"/items/-","value":...} appends — applying it twice adds twice. If you want safe retries, either use a test op to assert state first, or design your ops so re-application is a no-op (use replace on a fixed path instead of add to /items/-).
  • Use the right Content-Type. RFC 6902 = application/json-patch+json; RFC 7396 = application/merge-patch+json. Servers usually branch on this.
  • Optimistic concurrency. Combine a JSON Patch test op (or an If-Match ETag header) so concurrent writers can't silently overwrite each other.

Libraries Worth Knowing

For JSON Patch, fast-json-patch is the de-facto npm package — it applies, generates (diff two documents to produce a patch), and observes (track changes to a watched object). For JSON Merge Patch, the rules are tiny enough to inline, but json-merge-patch implements them with the null-deletion edge cases handled.

Applying Patches in Code

// JavaScript — fast-json-patch implements RFC 6902
import { applyPatch } from 'fast-json-patch';
const updated = applyPatch(document, patchOps).newDocument;

// JSON Merge Patch is trivial to apply by recursion, but a library
// (e.g. json-merge-patch) handles the null-deletion rules correctly.

After applying a patch, you can confirm the change is exactly what you intended by diffing the before and after — see How to Compare Two JSON Files or paste both into JSON Diff.

Frequently Asked Questions

What's the difference between JSON Patch and JSON Merge Patch?

JSON Merge Patch (RFC 7396) is a partial copy of the document where null deletes a key. JSON Patch (RFC 6902) is an explicit array of operations (add, remove, replace, move, copy, test) targeting JSON Pointer paths. Merge Patch is simpler; JSON Patch is more powerful.

Why can't JSON Merge Patch set a field to null?

Because in Merge Patch null is the signal to delete a key. If you need to store an actual null value, use JSON Patch with a replace op.

Which Content-Type should I use?

application/merge-patch+json for Merge Patch and application/json-patch+json for JSON Patch, both sent with the HTTP PATCH method.

How do I edit one element of an array?

Use JSON Patch with a path like /items/2, or append with /items/-. Merge Patch can only replace the entire array.

Related Tools & Reading