lychee: a Rust link checker for Markdown, HTML and live sites
⚡ Fast, async, stream-based link checker written in Rust. Finds broken URLs and mail addresses inside Markdown, HTML, reStructuredText, websites and more!
At a glance
- What is it?
- lycheeverse/lychee is an async link checker distributed as a CLI, a Rust library and a GitHub Action. It is fast to adopt, but its defaults and its Rustls-only TLS stack are decisions you should understand before wiring it into CI.
- Who is it for?
- Adopt lychee if you maintain documentation, a static site or a repository full of Markdown and want broken links caught on every push; the pre-commit hook, the CLI and the GitHub Action all cover that ground without a service to run. Skip it if you need JavaScript-rendered pages checked or you are pinned to an OpenSSL-only environment, because the project states it has dropped OpenSSL in favour of Rustls.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem lychee targets: link rot in files you control
Documentation rots quietly. A page moves, a domain lapses, a mail address is retired, and nothing in the build fails. lychee exists to make that failure loud. The README describes it as "a fast, async, stream-based link checker written in Rust" that "finds broken hyperlinks and mail addresses in websites and Markdown, HTML, and other file formats".
The audience is narrow and identifiable: people who keep content in a repository. That includes documentation sites, static site generators, README-heavy projects, and any pipeline where a pull request can introduce a dead URL. Because the project also ships as a GitHub Action (lycheeverse/lychee-action) and as a pre-commit hook (.pre-commit-hooks.yaml sits at the repository root), it is designed to run at commit time and at CI time, not as a periodic external audit. That distinction matters. lychee checks the links you already know about; it does not crawl the web looking for new ones.
How lychee works: async requests, a stream of extracted links
The architecture is visible in the repository layout. The workspace splits into lychee-lib and lychee-bin, with examples/ containing small programs named for individual concerns: extract, collect_links, client_pool, builder, chain, archive and simple. Those names describe the pipeline. Input is read, links are extracted from it, and the extracted set is fed to a pool of HTTP clients that issue requests concurrently.
Two properties follow from that design. First, extraction is separate from checking, so the same checker works across the file formats the README lists rather than being tied to one parser. Second, concurrency is pooled rather than one-request-per-thread, which is what the "async, stream-based" phrasing refers to. The library is published separately on docs.rs as lychee-lib, so the checking engine can be embedded in another Rust program without shelling out to the binary.
TLS is worth calling out because it is a deliberate narrowing. The README states that lychee previously allowed a choice between OpenSSL and Rustls, and that "it was decided to fully switch to Rustls and drop OpenSSL support", linking to pull request 1928. The same section asks users to report if this negatively affects them. That is an honest note, and it is also a constraint: environments that require OpenSSL for policy or platform reasons have no supported path in the current build.
Installing lychee on Linux, macOS and Windows
The README lists package manager routes for most platforms. On Ubuntu the documented command uses snap; on Arch Linux, pacman; on OpenSUSE Tumbleweed, zypper; on Alpine, apk with the caveat that the package is "available for Alpine Edge in testing repositories". macOS has Homebrew and MacPorts. Windows has scoop, WinGet (with the identifier lycheeverse.lychee) and Chocolatey. FreeBSD, Termux and Conda are also covered.
If you would rather not install a system package, the container image is the shortest path. The README documents the image name and the tag scheme, including an -alpine variant for each tag.
docker pull lycheeverse/lycheeTags documented in the README include latest for the most recent stable release, an X.Y.Z or X.Y form for a specific release, nightly for a build from the master branch, master as an alias of nightly, and sha-<sha> for a specific commit. The README marks latest as recommended.
For a Rust toolchain, cargo install lychee builds from source. The README notes that on APT/dpkg-based distributions you need build dependencies first, and gives the exact set.
apt install gcc pkg-config libc6-dev libssl-dev
cargo install lycheeThere is also cargo binstall lychee for pre-built binaries, and the releases page carries binaries for Linux, macOS and Windows. Feature flags are documented: email-check enables mail address checking via the mailify-lib crate and is enabled by default, while check_example_domains allows checking example domains such as example.com and is described as useful for testing. If you want a first real run, point the binary at a file rather than a whole site, and keep the configuration in a file. The repository ships lychee.example.toml and lychee.toml at the root, which is where the documented config keys live.
Where lychee is the wrong tool
The clearest limitation is scope of extraction. lychee finds links inside the formats it parses. A site that builds its navigation from a JavaScript bundle, or a single-page application whose anchors only exist after hydration, presents links that are not in the source lychee reads. The README does not claim a headless browser; it lists Markdown, HTML, reStructuredText and websites as supported inputs. Treat a clean lychee run as evidence about the files and responses it actually saw, not as proof that every user-visible link resolves.
Transient failures are the second trap. A remote host that returns a 5xx during a CI run, or that rate-limits a burst of parallel requests, produces a failure that is not a content defect. The README points to a "Troubleshooting and Workarounds" section, which is the right place to look for exclusion and retry behaviour rather than assuming defaults are tuned for your target sites. This is also where the async design cuts both ways: concurrency makes a large site finish quickly, and it also makes you more likely to be throttled.
The third case is the OpenSSL one already mentioned. If your environment cannot use Rustls, the current build is not for you.
lychee compared with linkchecker and markdown-link-check
The README includes a feature comparison table and labels it "best-effort", asking readers to open a pull request when information is outdated. That framing is worth respecting: the table is a starting point, not an authority.
The comparison lists linkchecker as Python and markdown-link-check as JavaScript, against lychee's Rust. The practical difference is deployment shape. linkchecker is a long-standing Python tool, which means it fits environments where a Python runtime is already present and where you may want to script around it in Python. markdown-link-check is JavaScript and narrower by name: it targets Markdown, and it slots into a Node-based build. lychee's own pitch is breadth of input plus a compiled binary that needs no language runtime, and the same engine is exposed as lychee-lib for embedding. If your pipeline is Node-only and your content is only Markdown, markdown-link-check is a smaller dependency. If your pipeline is polyglot and your content spans Markdown, HTML and reStructuredText, the compiled binary avoids adding a runtime. The table also lists awesome_bot (Ruby), muffet (Go), broken-link-checker (JS) and fink (PHP), so the space is not short of options; lychee's distinguishing claim is the combination of Rust, async checking and a library API.
Maintenance, licensing and what a version bump costs
The repository is not archived, and the last push was on 2026-09-21. Releases are frequent: a nightly tag dated 2026-09-21, and lychee-v0.24.2 with lychee-lib-v0.24.2 dated 2026-05-01. The workspace version in Cargo.toml is 0.24.2, matching the tagged release, so the library and the binary version in step.
That release cadence has a cost. If you track nightly or master, you are tracking a branch the README itself calls bleeding-edge, and the Docker tag list treats master as an alias of nightly. Pin to a released tag such as 0.24.2 or 0.24 if you want reproducibility, and treat the versioned library crate as a separate upgrade decision from the CLI, since they are published as distinct artifacts. The presence of Cargo.lock in the repository, and the Makefile target cargo install --path lychee-bin --locked, indicate that locked builds are an intended workflow.
Licensing is dual. The repository root contains LICENSE-APACHE and LICENSE-MIT, and the project metadata lists Apache-2.0. Dual Apache-2.0/MIT is a permissive arrangement, but the choice of which terms you rely on is yours to make with your own legal review, not something this article can settle. Note also that the Dockerfile's production stage is built on debian:trixie-slim and installs ca-certificates and tzdata, which matters if you have opinions about base images in your supply chain.
Editorial conclusion
Adopt lychee if you maintain documentation, a static site or a repository full of Markdown and want broken links caught on every push; the pre-commit hook, the CLI and the GitHub Action all cover that ground without a service to run. Skip it if you need JavaScript-rendered pages checked or you are pinned to an OpenSSL-only environment, because the project states it has dropped OpenSSL in favour of Rustls. Before you commit, run the binary against your own content with a config file derived from lychee.example.toml, confirm which hosts need exclusion, and check the licence files (LICENSE-APACHE and LICENSE-MIT) against your distribution policy.
Frequently asked questions
How do I install lychee on Linux?
The README documents several routes: snap install lychee on Ubuntu, pacman -S lychee on Arch Linux, zypper in lychee on OpenSUSE Tumbleweed, and apk add lychee on Alpine Edge testing repositories. You can also use cargo install lychee, cargo binstall lychee, or pull the lycheeverse/lychee Docker image.
How do I use lychee to check links?
The README documents three usage surfaces: a command-line utility, the lychee-lib library on docs.rs, and the lycheeverse/lychee-action GitHub Action. Configuration keys live in the lychee.example.toml and lychee.toml files shipped at the repository root, and the website's command-line flags guide lists the options for customising a run.
How do I install lychee?
Beyond the Linux package managers, the README lists brew install lychee and sudo port install lychee on macOS, scoop install lychee, winget install --id lycheeverse.lychee and choco install lychee on Windows, plus pkg install lychee on FreeBSD and Termux and conda install lychee -c conda-forge. Pre-built binaries for Linux, macOS and Windows are on the releases page.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lycheeverse-lychee)