fastjsondiff
A high-performance Python library for comparing JSON payloads, powered by a Zig core for maximum speed.
Features
- Fast: Zig-powered core delivers sub-millisecond comparisons for typical payloads
- Complete: Detects added, removed, and changed values with full path reporting
- Deep: Handles arbitrarily nested structures (objects and arrays)
- Scalable: Efficiently processes multi-megabyte JSON files
- Pythonic: Clean API with iteration, filtering, and serialization support
Installation
pip install fastjsondiff-zig
Or using uv:
uv add fastjsondiff-zig
Development Installation
# Clone the repository
git clone https://github.com/adilkhash/fastjsondiff.git
cd fastjsondiff
# Build the Zig core
cd fastjsondiff/_zig
zig build
cd ../..
# Install in development mode
pip install -e .
# Or using uv
uv pip install -e .
Quick Start
import fastjsondiff
# Compare two JSON strings
result = fastjsondiff.compare(
'{"name": "Alice", "age": 30}',
'{"name": "Bob", "age": 30, "city": "NYC"}'
)
# Check if there are differences
if result:
print(f"Found {len(result)} differences")
# Iterate over differences
for diff in result:
print(f"{diff.type.value}: {diff.path}")
print(f" old: {diff.old_value}")
print(f" new: {diff.new_value}")
Output:
Found 2 differences
changed: root.name
old: "Alice"
new: "Bob"
added: root.city
old: None
new: "NYC"
API Reference
compare(a, b, *, array_match="index")
Compare two JSON payloads and return their differences.
Parameters:
a: First JSON input (string or bytes)b: Second JSON input (string or bytes)array_match: Array comparison strategy ("index"for position-based comparison)
Returns: DiffResult containing all differences found
Raises:
InvalidJsonError: If either input is not valid JSONTypeError: If inputs are not string or bytes
result = fastjsondiff.compare('{"a": 1}', '{"a": 2}')
compare_files(path_a, path_b, *, array_match="index", encoding="utf-8")
Compare two JSON files.
Parameters:
path_a: Path to first JSON filepath_b: Path to second JSON filearray_match: Array comparison strategyencoding: File encoding (default: utf-8)
Returns: DiffResult containing all differences found
result = fastjsondiff.compare_files("old.json", "new.json")
DiffResult
Container for comparison results.
result = fastjsondiff.compare(json_a, json_b)
# Length and boolean
len(result) # Number of differences
bool(result) # True if any differences exist
# Iteration
for diff in result:
print(diff.path)
# Index access
first_diff = result[0]
# Filtering
added = result.filter(DiffType.ADDED)
removed = result.filter(DiffType.REMOVED)
changed = result.filter(DiffType.CHANGED)
# Summary
result.summary.added # Count of added items
result.summary.removed # Count of removed items
result.summary.changed # Count of changed items
result.summary.total # Total differences
# Metadata
result.metadata.paths_compared # Number of paths visited
result.metadata.max_depth # Maximum nesting depth
result.metadata.duration_ms # Comparison time in milliseconds
# Serialization
result.to_dict() # Convert to dictionary
result.to_json() # Convert to JSON string
result.to_json(indent=2) # Pretty-printed JSON
Difference
Represents a single difference.
diff.type # DiffType.ADDED, DiffType.REMOVED, or DiffType.CHANGED
diff.path # JSON path (e.g., "root.users[0].name")
diff.old_value # Previous value (None for ADDED)
diff.new_value # New value (None for REMOVED)
diff.to_dict() # Serialize to dictionary
DiffType
Enum of difference types:
from fastjsondiff import DiffType
DiffType.ADDED # Key/element exists in second input only
DiffType.REMOVED # Key/element exists in first input only
DiffType.CHANGED # Value differs between inputs
Path Format
Paths use dot notation for object keys and bracket notation for array indices:
root.name- Object keyroot.users[0]- Array elementroot.users[0].email- Nested path
Performance
Benchmarks on typical hardware:
| Payload Size | Keys | Time |
|---|---|---|
| 2 KB | 100 | 0.2 ms |
| 23 KB | 1,000 | 2.4 ms |
| 252 KB | 10,000 | 24 ms |
| 1.3 MB | 50,000 | 122 ms |
Examples
Detecting Configuration Changes
import fastjsondiff
old_config = '{"debug": false, "port": 8080}'
new_config = '{"debug": true, "port": 8080, "host": "0.0.0.0"}'
result = fastjsondiff.compare(old_config, new_config)
for diff in result:
if diff.type == fastjsondiff.DiffType.CHANGED:
print(f"Modified: {diff.path}")
elif diff.type == fastjsondiff.DiffType.ADDED:
print(f"New setting: {diff.path}")
Comparing API Responses
import fastjsondiff
import json
response_v1 = '{"users": [{"id": 1, "name": "Alice"}]}'
response_v2 = '{"users": [{"id": 1, "name": "Alice", "email": "alice@example.com"}]}'
result = fastjsondiff.compare(response_v1, response_v2)
if result:
print("API response changed:")
print(result.to_json(indent=2))
Filtering by Change Type
import fastjsondiff
from fastjsondiff import DiffType
result = fastjsondiff.compare(old_json, new_json)
# Get only added fields
new_fields = result.filter(DiffType.ADDED)
print(f"{len(new_fields)} new fields added")
# Get only removed fields
removed_fields = result.filter(DiffType.REMOVED)
print(f"{len(removed_fields)} fields removed")
Requirements
- Python 3.10+
- Zig 0.15.2 (for building from source)
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Run tests (
pytest tests/) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Metadata
Release files for fastjsondiff-zig 26.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastjsondiff_zig-26.1.tar.gz | 209.4 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastjsondiff_zig-26.1-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
Total release size: 644.3 kB
Release files / fastjsondiff_zig-26.1.tar.gz
| Download URL | fastjsondiff_zig-26.1.tar.gz |
|---|---|
| Size | 209.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3931059a8811d39a1807818f87e70266bcf48b44d065ab496ec44ed1c35bbd67
|
|
BLAKE2b-256 checksum How to use checksums |
325ee7d1eb9983820702664805a1a6fd98bf8aaae280494cbe807f6d0a581574
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Jan 16, 2026.
Transparency logRelease files / fastjsondiff_zig-26.1-py3-none-win_amd64.whl
| Download URL | fastjsondiff_zig-26.1-py3-none-win_amd64.whl |
|---|---|
| Size | 158.9 kB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
bb78dc76ff60e8d47f0b409b866b51db0927006a16fc6845f7321227271e463e
|
|
BLAKE2b-256 checksum How to use checksums |
f56220f23f6c038adbc8d67f6e7b9980a4c620bd73f579a573e5dddea1bb8a6e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Jan 16, 2026.
Transparency logRelease files / fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl
| Download URL | fastjsondiff_zig-26.1-py3-none-manylinux_2_17_x86_64.whl |
|---|---|
| Size | 199.7 kB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
2ac0c7159e5088f7944ac4379ca9c55443a9858fa6702e886efa5be32f72c291
|
|
BLAKE2b-256 checksum How to use checksums |
9763d78f4955105f8a9e88ae9fe7ff888c28006f212f04fb1b6e3c3cdc559852
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Jan 16, 2026.
Transparency logRelease files / fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl
| Download URL | fastjsondiff_zig-26.1-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 76.4 kB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a6444e37f19d377d2bd30d1ca1b9d9ad7a01fb4c3d898b07d5b5e4e5a77adcc2
|
|
BLAKE2b-256 checksum How to use checksums |
b3f491887def17b4e7e5258e94c3551b877cf65950911458539da3b7e1103804
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Jan 16, 2026.
Transparency log