Internal link validation

Overview

Document authors include links to related content within a project. A link destination might be:

  • Another page
  • A heading on another page
  • A heading on the same page

While useful and necessary for document consumers, internal links are prone to breakage as the project changes over time.

The problem

A link to a heading on another page typically looks something like:

/articles/article-1#section-2
------------------- ---------
       path         fragment

If someone changes the path of the target page, or the heading on the target page, they will break the link on the source page.

Example 1: Change the path

SequenceTypeDescription
1ThoughtThis page title is imperfect.
2ActionChange the page title.
3ThoughtThe URL doesn’t match the new title.
4ActionChange the path to match the new title.
5ResultLinks to this page are now broken.

Example 2: Change the heading

SequenceTypeDescription
1ThoughtThis section heading is imperfect.
2ActionChange the heading.
3Side effectThe id attribute of the HTML heading element changes.
4MistakeForget to search the site for link fragments pointing to the old heading.
5ResultLinks to the heading on this page are now broken.

The solution

Link checkers, both proprietary and open source1, can identify broken links including a fragment, if present. This is a good approach, and required for external link validation, but there is room for improvement:

  1. When used in CI/CD deployments, link checkers do not identify errors until a document author submits a pull request. This delays error identification and resolution, and requires another round of CI/CD testing.
  2. When used in development, document authors must (a) install the link checker locally, and (b) remember to periodically run the link checker.

You can address these deficiencies with a link render hook that checks both the path and fragment components of an internal link destination, with no external dependencies.

Hugo introduced the .Page.Fragments structure in v0.111.0, providing access to the heading ids on a page. See the tables of content article for more information.

The example in the link and image render hooks article validates the path and fragment portions of a link destination. If a document author runs hugo server while creating or editing pages, Hugo throws an error or warning (configurable) when rendering a broken link.

Immediate validation improves document quality, reduces CI/CD errors, and decreases time-to-publish.


  1. Muffet is a blazingly fast link checker written in Go which recursively scrapes and inspects all pages. It validates both internal and external links. ↩︎

Last modified: