Standards walkthrough

JSON Patch RFC 6902: a worked add and replace example

Follow a complete RFC 6902 JSON Patch example with replace and add operations, JSON Pointer paths, array appends, and safe application checks.

A patch is an ordered list of operations

RFC 6902 represents a patch as a JSON array. Each operation object has one op member and one path member, plus value or from when that operation requires it. The six defined operations are add, remove, replace, move, copy, and test. They run in array order, and each successful result becomes the input to the next operation.

The path is an RFC 6901 JSON Pointer, not a dot-separated JavaScript expression. An empty pointer selects the whole document. Each slash introduces a reference token; within a token, ~1 represents a slash and ~0 represents a tilde. Array indexes are decimal positions, while the special final token - is available to add a value after the last array item.

Start with explicit source and target documents

Suppose a profile name changes, a reviewer role is appended, and a last-login field is introduced. Writing both complete documents first makes the intended outcome reviewable before anyone generates a patch.

Source documentjson
{
  "profile": {
    "name": "Ada",
    "roles": ["admin", "author"]
  },
  "active": true
}
Target documentjson
{
  "profile": {
    "name": "Ada Lovelace",
    "roles": ["admin", "author", "reviewer"]
  },
  "active": true,
  "lastLogin": null
}

A semantic comparison should show three changes. Object-member display order is not part of the change, but the new role's array position is. Keeping source and target copies also lets you verify a generated patch by applying it and comparing the complete result with the target.

Read the generated operations in sequence

RFC 6902 patch generated for the examplejson-patch
[
  {
    "op": "replace",
    "path": "/profile/name",
    "value": "Ada Lovelace"
  },
  {
    "op": "add",
    "path": "/profile/roles/-",
    "value": "reviewer"
  },
  {
    "op": "add",
    "path": "/lastLogin",
    "value": null
  }
]

The replace operation requires /profile/name to exist. The first add uses - to append to the roles array. The second add creates lastLogin because its parent document exists. An add operation can create a final object member, but it cannot invent missing intermediate parents; adding /account/status would fail when /account is absent.

Applying these three operations produces the target document above. Other correct patches may exist: a generator could replace a larger subtree instead of emitting several small operations. Review whether the granularity matches your audit, conflict, and authorization requirements rather than treating shortest output as automatically best.

Use test operations and fail the whole application safely

A test operation checks that the value at a path equals an expected JSON value. Put it before a dependent mutation when a patch should apply only to a known version or state. If a normative requirement is violated or an operation fails, RFC 6902 says evaluation should stop and the patch document must not be considered successfully applied.

Guard a change with testjson-patch
[
  { "op": "test", "path": "/active", "value": true },
  { "op": "replace", "path": "/active", "value": false }
]

A local preview should leave the source unchanged when any operation fails. When JSON Patch is carried over HTTP PATCH, also follow the server's authorization, precondition, and atomicity rules. Never assume that a syntactically valid patch is permitted to change every referenced field.

Review paths, values, and boundaries

  • Confirm every path targets the intended object member or array position, including ~0 and ~1 escaping.
  • Check that remove and replace targets exist and that move or copy from paths exist.
  • Apply the complete sequence to a copy, then compare the result with the expected document.
  • Enforce size, depth, operation-count, authentication, and field-level authorization limits at the receiving boundary.
Standards consulted

Primary sources

The examples and boundaries in this guide are based on the specifications below and the versioned browser engines used by the linked tools.

  1. IETFRFC 6902 — JavaScript Object Notation (JSON) Patch

    Defines the JSON Patch document shape, six operations, sequential evaluation, errors, and application/json-patch+json media type.

    Read source
  2. IETFRFC 6901 — JavaScript Object Notation (JSON) Pointer

    Defines the pointer syntax and ~0 and ~1 token escaping used by JSON Patch paths.

    Read source
  3. IETFRFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format

    Defines the JSON values operated on by a JSON Patch implementation.

    Read source