JsonPatch
The JsonPatch module computes and applies deterministic patch documents for
JSON values. A patch is an ordered list of add, remove, and replace
operations addressed by JSON Pointer paths. Use it to describe the structural
difference between two JSON documents, serialize that difference, and replay
it without mutating the original input.
Models
A JSON Patch document (an ordered list of operations).
When to use
Use to store, serialize, pass, or validate complete patch documents.
Details
Represents a complete transformation as a readonly sequence of immutable operations. Operations are applied sequentially from first to last, and later operations observe the document state produced by earlier operations. An empty array represents a no-op patch and returns the original document.
See
- JsonPatchOperation for individual operation types
- get to generate patches from value differences
- apply to execute patches to transform documents
Signature
type JsonPatch = ReadonlyArray<JsonPatchOperation>Example
(Defining a multi-operation patch)
import { JsonPatch } from "effect"
const patch: JsonPatch.JsonPatch = [ { op: "add", path: "/items/-", value: "apple" }, { op: "replace", path: "/count", value: 5 }, { op: "remove", path: "/oldField" }]
JsonPatch.apply(patch, { items: [], count: 3, oldField: "value" }) // => { items: ["apple"], count: 5 }JsonPatchOperation type
A single JSON Patch operation.
When to use
Use to manually construct patch operations, accept patch operations from callers, or type-check patch operation structures.
Details
Represents one transformation step in a JSON Patch document. This is a subset
of RFC 6902, restricted to operations that can be applied deterministically
without additional context. All fields are readonly, paths use JSON Pointer
syntax, and the empty string "" refers to the root document. Operations are
discriminated by the op field, and the optional description field can be
used for documentation.
See
Signature
type JsonPatchOperation = { readonly description?: string; readonly op: "add"; readonly path: string; readonly value: Schema.Json;} | { readonly description?: string; readonly op: "remove"; readonly path: string;} | { readonly description?: string; readonly op: "replace"; readonly path: string; readonly value: Schema.Json;}Example
(Defining all operation types)
import { JsonPatch } from "effect"
const addOp: JsonPatch.JsonPatchOperation = { op: "add", path: "/users/-", value: { id: 1, name: "Alice" }}
const removeOp: JsonPatch.JsonPatchOperation = { op: "remove", path: "/users/0"}
const replaceOp: JsonPatch.JsonPatchOperation = { op: "replace", path: "/users/0/name", value: "Bob"}
Array.of(addOp.op, removeOp.op, replaceOp.op) // => ["add", "remove", "replace"]Transforming
Applies a JSON Patch to a JSON document.
When to use
Use to execute patches generated by get, transform documents with manually constructed patches, or process patch operations from external sources.
Details
Executes patch operations sequentially, so later operations see changes made
by earlier operations. It never mutates the input document; array and object
operations copy the affected containers. An empty patch returns the original
reference, and a root replace (path: "") returns the provided value
directly.
Gotchas
Invalid paths, missing properties, and out-of-bounds array indices throw errors.
See
- get to generate patches from value differences
- JsonPatchOperation for the operation types being applied
Signature
declare function apply(patch: JsonPatch, oldValue: Json): JsonExample
(Applying a patch)
import { JsonPatch } from "effect"
const document = { items: [1, 2, 3], total: 6 }const patch: JsonPatch.JsonPatch = [ { op: "add", path: "/items/-", value: 4 }, { op: "replace", path: "/total", value: 10 }]
JsonPatch.apply(patch, document) // => { items: [1, 2, 3, 4], total: 10 }Computes a structural patch that transforms oldValue into newValue.
When to use
Use to compute a JSON Patch from before and after JSON documents, detect structural changes, or create deterministic update operations.
Details
Generates a structural diff between two JSON values, producing a patch that
yields newValue when applied to oldValue. It returns an empty array when
values are identical, recursively diffs nested structures, emits root
replace operations for primitive changes, and processes object keys in
sorted order for stable output.
Gotchas
Arrays are compared by index position, with no move or copy detection. Array removals are emitted from highest to lowest index to prevent index shifting. The output is deterministic but not guaranteed to be minimal.
See
- apply to apply the generated patch to a document
- JsonPatchOperation for the operation types in the patch
Signature
declare function get(oldValue: Json, newValue: Json): JsonPatchExample
(Computing object diff)
import { JsonPatch } from "effect"
const oldValue = { users: [{ id: 1, name: "Alice" }], count: 1 }const newValue = { users: [{ id: 1, name: "Bob" }, { id: 2, name: "Charlie" }], count: 2 }
const patch = JsonPatch.get(oldValue, newValue)patch[0] // => { op: "replace", path: "/count", value: 2 }patch[1] // => { op: "replace", path: "/users/0/name", value: "Bob" }patch[2] // => { op: "add", path: "/users/1", value: { id: 2, name: "Charlie" } }