fastjsonpatch
A drop-in, faster jsonpatch
(RFC 6902 JSON Patch) for Python.
make_patch and apply run in Rust and return the same patches and the same
documents, and raise exceptions with the same types and messages, as jsonpatch 1.34.
In the benchmarks below, making a patch is 9-57x faster and applying one 6-27x faster.
pip install fastjsonpatch
import fastjsonpatch as jsonpatch # the only line you change
src = {"name": "web", "replicas": 3, "ports": [80, 443]}
dst = {"name": "web", "replicas": 5, "ports": [80, 443, 8080]}
patch = jsonpatch.make_patch(src, dst)
patch.patch
# [{'op': 'replace', 'path': '/replicas', 'value': 5},
# {'op': 'add', 'path': '/ports/2', 'value': 8080}]
patch.apply(src) == dst # True; src is not modified
jsonpatch.apply_patch(src, [{"op": "remove", "path": "/ports/0"}])
# {'name': 'web', 'replicas': 3, 'ports': [443]}
Python 3.12+ (CPython). Prebuilt wheels for Linux (x86_64 and aarch64, glibc and
musl), macOS (Apple Silicon and Intel) and Windows (x64); one wheel per platform covers
every Python from 3.12 on. The only dependency is jsonpointer.
Why
JSON Patch describes a change to a JSON document as a list of operations (add,
remove, replace, move, copy, test). It is a media type for HTTP PATCH
requests (application/json-patch+json), Kubernetes accepts it
(kubectl patch --type=json), and it can store or send the difference between two
versions of a document.
jsonpatch is written in pure Python. In the measurements below:
make_patchon a 10,000-record document takes 290 ms, and diffing two Kubernetes OpenAPI specs (3.7 MB and 3.8 MB) takes 136 ms.applydeep-copies the whole document first, so a 3-operation patch on the 3.8 MB Kubernetes spec takes 71 ms, against 21 µs when applied in place.- Applying or computing a patch on a small REST resource takes 47-74 µs per call.
fastjsonpatch keeps jsonpatch's behaviour exactly and moves these hot paths to Rust, so existing code gets faster without changes.
Speed
Measured on Linux x86_64, Python 3.13 (times are the best of several runs).
Real-world data:
| scenario | size | jsonpatch | fastjsonpatch | speedup |
|---|---|---|---|---|
| Kubernetes OpenAPI v1.33 (3.7 MB) → v1.34 (3.8 MB): make_patch | 283 ops | 136.4 ms | 9.6 ms | 14x |
| Kubernetes OpenAPI v1.33 → v1.34: apply | 283 ops | 78.0 ms | 11.4 ms | 7x |
| 3-op patch on the v1.34 spec | 3.8 MB | 71.1 ms | 10.1 ms | 7x |
3-op patch on the v1.34 spec, in_place=True |
3.8 MB | 21.2 µs | 4.7 µs | 4x |
| PyPI metadata snapshots (8k records): make_patch | 2,487 ops | 255.2 ms | 12.1 ms | 21x |
| PyPI metadata snapshots: apply | 2,487 ops | 91.7 ms | 14.0 ms | 7x |
| REST resource, apply_patch per request | ×1000 | 47.4 ms | 7.5 ms | 6x |
| REST resource, make_patch per request | ×1000 | 74.4 ms | 5.6 ms | 13x |
Synthetic records shaped like {"id", "name", "score", "tags": [..], "meta": {..}}:
| workload | ops | make_patch: jsonpatch | fastjsonpatch | speedup | apply: jsonpatch | fastjsonpatch | speedup |
|---|---|---|---|---|---|---|---|
| 10k records, 100 field edits | 100 | 292.61 ms | 5.26 ms | 56x | 89.38 ms | 7.90 ms | 11x |
| 10k records, insert 1 at front | 49911 | 669.77 ms | 42.78 ms | 16x | 535.21 ms | 72.35 ms | 7x |
| 10k records, delete 50 | 44900 | 636.53 ms | 40.46 ms | 16x | 563.20 ms | 63.45 ms | 9x |
| 10k records, move 20 | 26305 | 434.93 ms | 24.38 ms | 18x | 325.64 ms | 41.03 ms | 8x |
| 2k ints, insert 1 at front | 1 | 17.04 ms | 1.91 ms | 9x | 581 µs | 21 µs | 27x |
| small config (200 keys), 1 edit | 1 | 1.98 ms | 35 µs | 57x | 464 µs | 32 µs | 15x |
Python 3.14 made copy.deepcopy about 1.5x faster, so on 3.14 jsonpatch's apply on
a large document is faster too; on the "10k records, 100 field edits" workload the
apply speedup drops from about 11x to about 6x. The make_patch speedup stays about
the same. Run python bench/compare.py (from the source distribution) to measure on
your own machine.
Why it is faster
make_patch. jsonpatch walks both documents in Python and compares every scalar
with json.dumps(a) == json.dumps(b). Profiling the "10k records" workload with
cProfile puts about 40% of the time in json.dumps and about a third in isinstance
checks against abstract base classes (MutableMapping, MutableSequence).
fastjsonpatch walks the documents in Rust over the CPython objects directly (no
conversion to a Rust data structure), compares values natively with the same rules as the json.dumps comparison (1, 1.0 and True
are all different, -0.0 != 0.0, NaN equals NaN), keeps the current path on a stack,
and takes a single lockstep pass when two dicts have the same keys in the same order.
It is a port of jsonpatch's DiffBuilder, so it produces the same operations in the
same order, including detected moves.
apply. jsonpatch first runs copy.deepcopy on the document (so the original is
not modified), then builds a JsonPointer and an operation object for each operation.
For a small patch on a large document the copy is nearly all of the time.
fastjsonpatch copies each dict and list with one C call and only recurses into values
that are themselves containers; it keeps deepcopy's semantics (shared and cyclic
references are copied once) but skips the bookkeeping for containers referenced only
once. It then resolves the paths and runs the operations without creating
JsonPointer or operation objects.
Compatibility
fastjsonpatch is jsonpatch's own module (BSD licensed) with three methods routed to
Rust: JsonPatch.__init__ (validation), JsonPatch.from_diff (make_patch) and
JsonPatch.apply (apply_patch). Everything else is jsonpatch's code, so the public
names are the same: JsonPatch, make_patch, apply_patch, JsonPatch.from_string,
the operation classes, DiffBuilder, multidict, and the exceptions
JsonPatchException, InvalidJsonPatch, JsonPatchConflict, JsonPatchTestFailed
(with the same hierarchy, and JsonPointerException from jsonpointer).
The Rust code handles the common case and hands anything else back to the original Python code, so results never differ:
- make_patch: values it cannot reproduce exactly (non-JSON types that need
comparing, dict or list subclasses, a custom
dumps=, nesting deeper than 1000) are diffed by the originalDiffBuilder. - apply: works on plain dicts and lists. An operation that would fail, or that touches anything else, is run by the original operation classes before anything is mutated, so errors have the same type and message.
applyand validation use the original code for a custompointer_cls, a subclass with customoperationsor an overridden_get_operation, and patches that are not lists or tuples.make_patchuses it for a customdumps=orjson_dumper.
Known differences:
- The exception classes belong to fastjsonpatch. An exception raised by the original
jsonpatchpackage (for example inside another library that imports it) is not caught byexcept fastjsonpatch.JsonPatchConflict, and vice versa. - A value that is not a dict, list or JSON scalar inside a document being applied to
is copied with
copy.deepcopyon its own, so aliasing between such values is not preserved. __version__is fastjsonpatch's version, and jsonpatch's__author__and__website__are not defined.
fastjsonpatch.__jsonpatch_version__ says which jsonpatch release the behaviour
matches (currently 1.34).
How it is tested
About 1,570 tests. CI runs them with Python 3.12, 3.13 and 3.14 on Linux (x86_64 and aarch64, glibc), macOS (arm64 and x86_64) and Windows (x64); the musl wheels are built but not tested in CI:
- Parity: random documents, mutations and patches (valid and invalid) run through
both fastjsonpatch and jsonpatch 1.34, comparing the resulting patches and documents
by
reprand errors by type and message. Also covers aliasing, cycles, non-JSON values, subclasses, deep nesting and every fallback path. - jsonpatch's own test suite and doctests, run against fastjsonpatch.
- RFC 6902 conformance: the json-patch-tests suite.
The source distribution includes the tests and the benchmark.
Development
pip install maturin
maturin develop --release
pip install "jsonpatch==1.34" pytest # jsonpatch is the reference for the parity tests
pytest tests
python bench/compare.py # speed vs jsonpatch on this machine
See MAINTAINING.md for releases and upkeep.
License
BSD-3-Clause. The Python module and the diff algorithm come from jsonpatch
(Copyright (c) 2011 Stefan Kögl, BSD). The licenses of the Rust crates compiled into
the wheels are in THIRD_PARTY_LICENSES.md.
Metadata
Release files for fastjsonpatch 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastjsonpatch-0.1.2.tar.gz | 58.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| fastjsonpatch-0.1.2-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| fastjsonpatch-0.1.2-cp312-abi3-musllinux_1_2_x86_64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ x86-64 | Details |
| fastjsonpatch-0.1.2-cp312-abi3-musllinux_1_2_aarch64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ ARM64 | Details |
| fastjsonpatch-0.1.2-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| fastjsonpatch-0.1.2-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| fastjsonpatch-0.1.2-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
| fastjsonpatch-0.1.2-cp312-abi3-macosx_10_12_x86_64.whl | CPython 3.12 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 2.1 MB
Release files / fastjsonpatch-0.1.2.tar.gz
| Download URL | fastjsonpatch-0.1.2.tar.gz |
|---|---|
| Size | 58.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9448a80f841ce4c07eebf750c2183dd0ec4ca589ea20f7d45fed825a0ac12156
|
|
BLAKE2b-256 checksum How to use checksums |
ea5173c1cdf265689109826b83351992ade45c838f6375f4b4f1243f33aab961
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-win_amd64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 152.4 kB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
32d47f774894286a1f5ea4b179127f22a618c081d703413368beae94afc5788c
|
|
BLAKE2b-256 checksum How to use checksums |
4597a65bce75b6fdab8a7febe7bfb582dd0b0a62573ff95e527ddad2b81e5f8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-musllinux_1_2_x86_64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 470.7 kB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
f52592ad6bb536494609d9cacb2b5e1133873df08a01bdda1a9bce6bbea563c0
|
|
BLAKE2b-256 checksum How to use checksums |
d83ff1b0f2999c992a91815effa4c3ef266591417a7264e620339960f185a7bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-musllinux_1_2_aarch64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 435.3 kB |
| Tags | CPython 3.12 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
3a53f9dce4f3d84af9292278b31c254e39cbc08aceed80edc10c6ad9640f836e
|
|
BLAKE2b-256 checksum How to use checksums |
7271d35b37c809fd23a033f7599c837751b73571cb6dd3b09196f06102042315
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 259.2 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
41f2564142d12dbaa04768e8150c8e6119a12373ccdce21df11c98b541b0e364
|
|
BLAKE2b-256 checksum How to use checksums |
4b6361ece2970bde8e001958b3c97e127f7fff8300eea26dfc9697b6aba1cbd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 256.5 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
f9a0246744ec36b79c1273b2bdf1528d0a02ba71aea4c0859d1af8544c181601
|
|
BLAKE2b-256 checksum How to use checksums |
2933511848559ab27fe5621cfa70c415649130af4279ac2329212ca7966384e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 241.5 kB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
75f18259957e449ee855fbd34ab3b15e83d59338f8382e8dab02ab412962656a
|
|
BLAKE2b-256 checksum How to use checksums |
849f279ec6fe2cec792ecbe74b643c3a75ab5429c6f432200b0ae8eb340f85f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / fastjsonpatch-0.1.2-cp312-abi3-macosx_10_12_x86_64.whl
| Download URL | fastjsonpatch-0.1.2-cp312-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 254.3 kB |
| Tags | CPython 3.12 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
33de59fb437fdd144a4dfe901cb8f37978dab317b606e87cc76677bf649a1249
|
|
BLAKE2b-256 checksum How to use checksums |
e27cee42b82b9a6c63e0545b8bbc1f3dbcb50b36487fa586c447808b5b88376d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log