Link checking

How the site’s links are checked, locally and in CI.

The site is link-checked with Lychee, backed by a committed cache of external-link results (see Link cache).

To check links locally, run:

npm run check:links

Common commands

CommandChecking scope
check:linksWhole site
check:links:internalWhole site, offline (no external links)
check:links:diffChanged files only
fix:refcacheAlias of check:links; use it to refresh the link cache

The check:links and check:links:internal scripts run over a build of BUILD_KIND; check:links:diff checks files from the existing public/ build. For details, see Build kinds: full and lean.

Configuration

Lychee runs over the built site (public/) using the generated, git-ignored lychee.toml. The generate:config:links script derives it from lychee.base.toml plus an exclude_path block computed from page front matter, which has two sources:

  • link_check_exclude_path — a list of site-relative path regexes for pages the link checker must skip, such as blog pagination and old blog posts; see content/en/blog/_index.md. Start a pattern with ^(../)? to have it cover every locale: the optional ../ matches a two-letter locale path segment such as ja/.
  • drifted_from_default: truedrifted localized pages. Links from a drifted page aren’t checked, since they may be stale, but the page remains a valid link target: inbound links from in-sync pages, including fragments, are still validated.

Link cache

External-link check results are cached in .lycheecache, which is under version control so that checks only fetch URLs that are new or whose cache entries have expired. Lychee caches successful results only, so failures are retried on every run.

If you add or change external links, the check updates the cache; commit the .lycheecache changes along with your content changes, or comment /fix:refcache on your PR to have the bot do it. For details, see BUILD and CHECK LINKS.

Cache refresh and housekeeping workflows

The following workflows are scheduled daily and run a link checking command over a full build:

WorkflowLink-check command
Refcache refreshfix:refcache (after pruning)
Housekeeping (fix-and-test:all)fix:refcache

Refcache refresh prunes the oldest cache entries (the count is a workflow input) and re-runs the link check, which refreshes the cache entries for the pruned URLs that are still used in the site.

The housekeeping workflow runs fix-and-test:all, which calls fix:refcache and deliberately skips check:links so links are checked exactly once.

In CI

The check-links.yml workflow builds the site once (lean) and shares that artifact with the CHECK LINKS job, so local runs and CI check the same build. The job fails if any link check fails, or if the run leaves the committed .lycheecache stale.