Skip to content

flightcontrolhq/fast-json-schema-patch

Repository files navigation

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 Plan object that can be used with JsonSchemaPatcher and StructuredDiff.

JsonSchemaPatcher

The main class for generating patches.

new JsonSchemaPatcher({ plan })

  • plan: A Plan object created by buildPlan that 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: A Plan object created by buildPlan that describes your data structure and desired diffing strategies.

structuredDiff.execute(config)

  • config: An StructuredDiffConfig object 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 from JsonSchemaPatcher. If not provided, patches will be generated automatically.
  • Returns: An StructuredDiffResult object containing parentDiff and a record of childDiffs.

🔬 Benchmarking Your Use Case

Run benchmarks on your own data:

# Run the benchmark suite
bun run compare

🔗 Related Standards

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published