check-json5
A pre-commit hook that checks whether .json files parse as
JSON5 (JSON with comments, trailing commas, and more). It replaces the
standard check-json hook, which rejects any comment, and it still parses ordinary JSON with the
fast C parser.
-
Every failure names its place, as
file:line:col: message, so editors and terminals link straight to it. A duplicate key also gets its path, and every repeat in a file is listed:config.json:4:5: duplicate key $.server.port config.json:9:3: duplicate key $.plugins[2].name
-
On GitHub Actions, each failure is also an annotation on the line of the pull request diff.
-
Accepts
NaNandInfinity(both parsers allow them) unless--strictcovers the file.
Source on GitHub, mirrored on GitLab. Release notes are in the CHANGELOG.
Usage
In .pre-commit-config.yaml, under repos:, add:
- repo: https://github.com/simonvanlierde/check-json5
rev: v1.4.1
hooks:
- id: check-json5
If you already use the original check-json hook, remove it. A file passes when it parses as
JSON5 and has no duplicate keys. The hook picks files by name: .json, .jsonc, .json5,
.geojson, .jsonld, Tailscale's .hujson and .jwcc, VS Code's .code-workspace and
.code-snippets, .webmanifest, and .babelrc. check-json picks them by file type instead,
so after the swap files such as .ipynb notebooks are no longer checked. If you need them, add
them with files:.
Some tools read their JSON files with a strict parser: a comment in package.json passes a JSON5
check and then breaks npm. Name those files with --strict to hold them to strict JSON (no
comments, trailing commas or NaN). Each pattern matches the file name at any depth, or the whole
path when it contains a /. * also matches across /. A leading ! exempts files, and the
last matching pattern wins:
- id: check-json5
args: [--strict, "*.json", --strict, "!tsconfig*.json", --strict, "!.vscode/*"]
The hook is also on PyPI as a command: uvx check-json5 --strict package.json config/*.json.
Performance
Strict JSON, and JSON that adds only comments and trailing commas, go through the C-speed stdlib
json parser. Only files that use more of JSON5 (single quotes, unquoted keys, hex numbers) fall
back to the pure-Python json5 parser, which is slow on large
files. Every path finds duplicate keys.
Time for one hook call per file (strict JSON, taking the fast path), best of 10 runs of
uv run python scripts/bench.py on 2026-10-11 (Intel i9-14900KF, Linux, Python 3.13.7, json5 0.15.0,
load average 1.5):
| File size | Before (json5 only) |
After (fast path) | Speedup |
|---|---|---|---|
| 1 KB | 2.5 ms | 0.02 ms | ~100× |
| 47 KB | 123 ms | 0.19 ms | ~660× |
| 483 KB | 1.3 s | 1.8 ms | ~750× |
| 2 MB | 5.4 s | 7.7 ms | ~700× |
Timings vary between runs by up to 2× on a loaded machine. The 1 KB fast-path time is close to the timer's resolution, so its speed-up ranged from ~80× to ~100× across runs.
bash scripts/bench.sh --jsonc (needs hyperfine) times
whole hook runs on files with only comments and trailing commas, such as most tsconfig.json and
.vscode/settings.json files, against the json5 parser alone (2026-10-13, Intel i9-14900KF,
Linux, Python 3.13, json5 0.15.0, one pinned core, load average 2.5):
| JSONC file | json5 alone |
Hook | Speedup |
|---|---|---|---|
| 50 KB | 193 ms | 18 ms | ~11× |
| 500 KB | 2.1 s | 46 ms | ~45× |
| 2 MB | 7.8 s | 141 ms | ~56× |
About 12 ms of each run is Python starting up. Files that need the json5 parser are no faster.
On tiny strict-JSON files the saving disappears next to that startup cost. It matters on large
files and on repositories with many JSONC files. Without --jsonc, scripts/bench.sh times
strict-JSON files of 50 KB, 500 KB and 2 MB, and --quick times the 50 KB file once.
Development
CI runs the lint, format, type and test commands below, with coverage reported to Codecov. The last two install and run the hooks in your own checkout:
uv sync # install dependencies
uv run ruff check --no-fix . # lint
uv run ruff format --check . # formatting
uv run ty check # types
uv run pytest --cov=check_json5 --cov-fail-under=95 # tests with coverage
uv run pre-commit install # run the hooks on every commit
uv run pre-commit run -a # run the hooks over the whole tree
Credits
I (Simon van Lierde) adapted this hook from the original check-json5 by Ben Mares, which is based on the pre-commit-hooks repository by Anthony Sottile and contributors. This version moves dependency management from Poetry to uv and adds the fast-path parser and benchmark above.
License
MIT, like the upstream projects it is based on (Ben Mares, pre-commit-hooks).
Metadata
Release files for check-json5 1.4.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 | |
|---|---|---|---|
| check_json5-1.4.1.tar.gz | 11.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| check_json5-1.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.1 kB
Release files / check_json5-1.4.1.tar.gz
| Download URL | check_json5-1.4.1.tar.gz |
|---|---|
| Size | 11.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
669e4c1fe483d332f4d90103c61dd8f8a1b0f2cbdd71c8054c99ad99ee3583a7
|
|
BLAKE2b-256 checksum How to use checksums |
4e46e82adcb5a3331195757cac911dcc83e3e02e3e859bd7a967b720fdffe449
|
| 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 13, 2026.
Transparency logRelease files / check_json5-1.4.1-py3-none-any.whl
| Download URL | check_json5-1.4.1-py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
522cb8ea2aa05ddd131a7c71828251c39f8160070972ccffe5966cd7fac11b72
|
|
BLAKE2b-256 checksum How to use checksums |
424ff6ea8f8d085fc0d9728a2aa9ecfd330b1f9cade13b68e9b68f83ecf5a880
|
| 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 13, 2026.
Transparency log