dotdiff
Semantic diff for JSON, YAML, TOML, and NDJSON. Compares two documents
structurally (not line by line) and prints a path-addressed change list
instead of textual noise. The sibling of dotpick:
dotpick extracts fields, dotdiff tells you what changed.
Install
cargo install dotdiff
Usage
dotdiff old.json new.json # text on a TTY, JSON when piped
dotdiff config.yaml config.json # cross-format works
cat new.json | dotdiff old.json - # `-` reads stdin
$ dotdiff old.json new.yaml
~ user.plan "free" -> "pro"
- user.trialEnds "2026-07-01"
+ user.seats 5
~ items[0].qty 1 -> 3
Output is the ~/+/- change list on a TTY, and structured JSON when piped:
$ dotdiff old.json new.json | jq .
{"identical": false, "changes": [
{"op": "changed", "path": "user.plan", "old": "free", "new": "pro"}
]}
Paths use dotpick's dotpath vocabulary
(user.plan, items[2].qty, ["quoted key"]), so you can feed a changed path
straight back into dotpick to inspect it.
Matching list items by key
By default arrays compare by position, so reordering a list reports everything
after the move as changed. Pass --array-key <field> to match objects in a list
by an identity field instead - order-independent, and far less noise:
# Without: a reordered list looks like 4 changes.
# With --array-key id: just the one real change.
$ dotdiff old.json new.json --array-key id
~ items[id=1].qty 1 -> 3
Formats
JSON, YAML, TOML, and NDJSON are detected per file (by extension, then content);
force both sides with --format. NDJSON is compared as an array of records, so
--array-key matches records across two streams. Everything is loaded into one
model, which is why cross-format diffing works.
Exit codes
| code | meaning |
|---|---|
0 |
identical |
1 |
differences found (the report is on stdout - not an error) |
2 |
an input could not be read or parsed |
3 |
usage error |
Exit 1 is a data state, not a failure (the diff/grep convention), so
dotdiff is scriptable as a gate: dotdiff a.json b.json && echo unchanged.
For agents (clispec)
dotdiff follows The CLI Spec: structured output on
stdout, structured error envelopes on the last line of stderr, a schema
subcommand whose development-branch output validates against the candidate
clispec.dev/schema/v0.3.json (checked by the test suite), and the
exit-1-on-differences contract declared as an outcome. Every command declares
effects: read_only; the published release remains on frozen v0.2 until v0.3
freezes.
dotdiff schema
License
MIT
Metadata
Release files for dotdiff 0.1.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 | Provenance | Actions |
|---|---|---|---|---|
| dotdiff-0.1.1.tar.gz | 36.3 kB | Without provenance | Details for dotdiff-0.1.1.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| dotdiff-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details for dotdiff-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
| dotdiff-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details for dotdiff-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
| dotdiff-0.1.1-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details for dotdiff-0.1.1-py3-none-macosx_11_0_arm64.whl |
| dotdiff-0.1.1-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details for dotdiff-0.1.1-py3-none-macosx_10_12_x86_64.whl |
Total release size: 2.5 MB
Release files / dotdiff-0.1.1.tar.gz
| Download URL | dotdiff-0.1.1.tar.gz |
|---|---|
| Size | 36.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
14d4f89588f64b024891e76e1af8f5715500e69a774796562ebeb4e47cba7132
|
|
BLAKE2b-256 checksum How to use checksums |
bd97ba52e3bc4e1155e4fc68c934fe6f1e82ae0fd728df6a45c22fd490932f55
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / dotdiff-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | dotdiff-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 648.1 kB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
bf75770366520b979e698346505f871d6d7587f0218455fb060921e99fd8aed7
|
|
BLAKE2b-256 checksum How to use checksums |
252f1b923065d8715f66af21f162042fdbaec0882f221bb5ed26905cba782750
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / dotdiff-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | dotdiff-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 604.5 kB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
94e7100b53cb884a7ae20042309c0b829d4a4572b2940f76a179ae58476e134e
|
|
BLAKE2b-256 checksum How to use checksums |
0dc633e18864117a8f50906a3aa0bbbef5bc246960fdb3497c10b92a39f35781
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / dotdiff-0.1.1-py3-none-macosx_11_0_arm64.whl
| Download URL | dotdiff-0.1.1-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 588.5 kB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c3cc5988d2aa5f90f1351ba130c90c1f450a75fdf4955f6c55fed00f794715c4
|
|
BLAKE2b-256 checksum How to use checksums |
a10cbfd14594c6132dc4ed9c6e21c2053f3db6a5eef627e93404ed93b32ecf4f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / dotdiff-0.1.1-py3-none-macosx_10_12_x86_64.whl
| Download URL | dotdiff-0.1.1-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 628.5 kB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
2e007389b05a3fdc5ae0fc4613f6f3b7b11bdee77cf9e2c7dd749c6a61cd03af
|
|
BLAKE2b-256 checksum How to use checksums |
0ad5f56d03a8c29033f020000ae237658cb849d9542340735672da809a966712
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for dotdiff 0.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.