fast-json-schema-patch
v0.4.0
Published
Ultra-fast, schema-aware JSON patch generation and human-readable diffing. A high-performance JSON patch library that leverages schema knowledge to generate efficient, semantic patches with tools for creating human-readable diffs suitable for frontend app
Readme
fast-json-schema-patch
🚀 Ultra-fast, Schema-Aware JSON Patch Generation with Human-Readable Diffing
fast-json-schema-patch is a high-performance JSON patching library designed to create efficient, schema-driven patches. It intelligently understands your data structure, enabling optimized, semantic diffs, and also provides fast, human-friendly diffing tools for frontend applications. It outperforms many popular alternatives in both speed and memory usage.
🧠 Schema-Driven Diffing Unlike generic JSON diff libraries, fast-json-schema-patch leverages schema-based diff plans to:
⚡ Optimize array diffing using the best strategy for each case (LCS, primary key matching, etc.).
🧩 Generate semantic patches that align with your data’s meaning, not just its shape.
🎯 Compare objects intelligently by focusing only on relevant fields.
💡 Ideal for applications where the JSON structure is known and schema-driven diffs are important.
📦 Installation
bun add fast-json-schema-patch🚀 Quick Start
The core of the library is the JsonSchemaPatcher, which uses a diff plan to optimize patch generation.
import { JsonSchemaPatcher, buildPlan } from 'fast-json-schema-patch';
// 1. Define a plan for your data structure, this needs to be done only once for a given schema
const plan = buildPlan({schema});
// 2. Instantiate the patcher with the plan
const patcher = new JsonSchemaPatcher({ plan });
// Original and modified documents
const original = {
users: [
{ id: 'user1', name: 'John Doe', status: 'active' },
{ id: 'user2', name: 'Jane Smith', status: 'inactive' },
],
};
const modified = {
users: [
{ id: 'user1', name: 'John Doe', status: 'online' }, // Changed
{ id: 'user3', name: 'Sam Ray', status: 'active' }, // Added
],
// user2 was removed
};
// 3. Generate the optimized patch
const patch = patcher.execute({original, modified});
console.log(patch);
// Output: [
// { op: "remove", path: "/users/1", oldValue: { id: 'user2', ... } },
// { op: "replace", path: "/users/0/status", value: "online", oldValue: "active" },
// { op: "add", path: "/users/-", value: { id: 'user3', ... } }
// ]A Note on RFC 6902 Compliance
This library extends the standard JSON Patch format by adding an oldValue field to remove and replace operations.
This addition makes UI rendering and state reconciliation easier but is not part of the strict RFC 6902 specification.
📋 Generating JSON Schema from Zod
If you're using Zod for runtime validation, you can easily generate JSON schemas for use with fast-json-schema-patch. Zod 4 introduced native JSON Schema conversion:
import * as z from "zod/v4";
import { JsonSchemaPatcher, buildPlan } from 'fast-json-schema-patch';
// Define your Zod schema
const userSchema = z.object({
users: z.array(z.object({
id: z.string(),
name: z.string(),
status: z.enum(['active', 'inactive', 'online'])
}))
});
// Convert Zod schema to JSON Schema
const jsonSchema = z.toJSONSchema(userSchema);
// Use the JSON schema to build a plan
const plan = buildPlan({ schema: jsonSchema });
const patcher = new JsonSchemaPatcher({ plan });This integration makes it seamless to leverage your existing Zod schemas for optimized JSON patching. For more details on Zod's JSON Schema conversion, see the official documentation.
🎨 Human-Readable Diffs with StructuredDiff
When you need to present diffs to users, raw JSON patches can be hard to work with. StructuredDiff helps you transform those patches into structured, human-readable diffs that are fast, memory-efficient, and frontend-friendly.
It organizes changes into:
Parent diffs: Changes outside of specific arrays.
Child diffs: Changes within a target array, keyed by unique identifiers.
This makes it easy to build side-by-side diff views or activity feeds.
import { StructuredDiff } from 'fast-json-schema-patch';
// Assuming `original`, `modified`, `patch`, and `plan` from the previous example
// 1. Instantiate the aggregator with the plan
const structuredDiff = new StructuredDiff({plan});
// 2. Execute the aggregation
const aggregatedResult = structuredDiff.execute({
original,
modified,
pathPrefix: '/users',
});
// 3. Use the result to render a UI
console.log(aggregatedResult.parentDiff); // Shows changes outside the /users array
console.log(aggregatedResult.childDiffs['user2']); // Shows user2 was removed
console.log(aggregatedResult.childDiffs['user3']); // Shows user3 was added🛠️ API Reference
buildPlan
Creates a plan for optimizing JSON patch generation based on a JSON schema.
buildPlan(options)
options: An object with the following properties:schema: A JSON Schema object that describes your data structure.primaryKeyMap(optional): A record mapping path prefixes to primary key field names.basePath(optional): The base path for the schema traversal.
- Returns: A
Planobject that can be used withJsonSchemaPatcherandStructuredDiff.
JsonSchemaPatcher
The main class for generating patches.
new JsonSchemaPatcher({ plan })
plan: APlanobject created bybuildPlanthat describes your data structure and desired diffing strategies.
patcher.execute({original, modified})
original: The original document to compare from.modified: The modified document to compare to.- Returns: An array of JSON Patch operations.
StructuredDiff
The main class for creating human-readable diffs.
new StructuredDiff({plan})
plan: APlanobject created bybuildPlanthat describes your data structure and desired diffing strategies.
structuredDiff.execute(config)
config: AnStructuredDiffConfigobject with the following properties:pathPrefix: The path prefix of the array to aggregate (e.g.,/users).original: The original document.modified: The modified document.patches(optional): Pre-computed patch array fromJsonSchemaPatcher. If not provided, patches will be generated automatically.
- Returns: An
StructuredDiffResultobject containingparentDiffand a record ofchildDiffs.
🔬 Benchmarking Your Use Case
Run benchmarks on your own data:
# Run the benchmark suite
bun run compare