linkbust
Find broken local links in your Markdown — relative file paths that don't
exist and #anchors that don't resolve to a heading. No network, zero
dependencies, fast enough to drop in a pre-commit hook.
linkbust
docs/setup.md:14 ✗ ./install.md (file not found)
README.md:8 ✗ #quick-start (no anchor "#quick-start" in this file)
guide.md:23 ✗ ./api.md#missing (no anchor "#missing" in ./api.md)
✗ 3 broken · 142 links checked in 26 file(s) (38 external skipped)
Why
Reorganize your docs, rename a file, tweak a heading — and quietly leave a trail of dead links behind. The checkers that catch this come with baggage:
- markdown-link-check works, but it pulls in ~9 dependencies and its main job is hitting external URLs over HTTP — slow, flaky in CI, and rate-limited.
- lychee is fast and thorough, but it's a Rust binary to install.
- The old Python option (
mlc) has been unmaintained since 2021.
linkbust does the part that breaks most often and is fully deterministic:
local links. It never makes a network request — so it's instant, works
offline, and won't flake your CI because someone's blog was down. That makes it
ideal for a pre-commit hook or a fast docs lint.
What it checks
- Relative file links —
[x](../docs/api.md), image sources — resolve on disk. - Anchors —
[x](#section)and[x](other.md#section)match a real heading (GitHub-style slug) or an explicit<a id="...">/id="...". - Reference links —
[text][ref]has a matching[ref]: …definition. - Links inside fenced/inline code are ignored, so examples don't trip it up.
It skips (never fetches) http(s), mailto:, protocol-relative //…, and
/absolute paths — checking those is a different, networked job.
Usage
linkbust # every .md under the current directory
linkbust README.md # a single file
linkbust docs/ CHANGELOG.md # files and/or directories (recursive)
| Option | |
|---|---|
--json |
machine-readable results |
-q, --quiet |
print nothing when everything's fine (great for hooks) |
--no-color |
exit 0 all local links resolve
exit 1 one or more broken links
exit 2 usage / read error
As a pre-commit hook
# .pre-commit-config.yaml
- repo: local
hooks:
- id: linkbust
name: linkbust
entry: linkbust
language: system
pass_filenames: false
Install
pip install linkbust # Python >= 3.8
npx linkbust # Node >= 18 (byte-for-byte port)
- PyPI: https://pypi.org/project/linkbust/
- npm: https://www.npmjs.com/package/linkbust
- GitHub: https://github.com/jjdoor/linkbust-py · linkbust (Node)
License
MIT
Release files for linkbust 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| linkbust-0.1.0.tar.gz | 10.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| linkbust-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:19.1 kB
Release files / linkbust-0.1.0.tar.gz
| Download URL | linkbust-0.1.0.tar.gz |
|---|---|
| Size | 10.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7774c28a797f903c956b451ccbcbe6fb210faa27283ca97bca4d1062a3b6cb51
|
|
BLAKE2b-256 checksum How to use checksums |
835ef1dc26990a55f6ccee06eca14844a68e3e2860abd028a0ce1ef671d14e72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|
Release files / linkbust-0.1.0-py3-none-any.whl
| Download URL | linkbust-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1a14ca61444525dff2812f18486e8c9a7fb7078a6327766d2098abd4f03317fc
|
|
BLAKE2b-256 checksum How to use checksums |
31b0aa96009dcdf49dff14db668b1b409d12c14b8a8a48c7f9a59a1951846bc6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|