Skip to main content

Hugo Hextra theme: in-content relative links must end in .md

·221 words·2 mins
Author
jeonck
Running a handful of Hugo/Docusaurus sites on GitHub Pages, and writing down the problems and fixes along the way.

On a docs site built with Hugo Hextra, some in-content relative links only break after deploy. If hugo server looks fine locally but the same page 404s on GitHub Pages, this is a likely cause.

Cause
#

Hextra’s link render hook (themes/hextra/layouts/_markup/render-link.html) only rewrites an internal link into a clean URL if the link target ends in .md.

{{/* summary of the logic inside render-link.html */}}
{{ if strings.HasSuffix $url.Path ".md" }}
  {{/* .GetPage resolves the page and rewrites to a clean URL */}}
{{ end }}

A link without .md never enters that branch — it’s emitted verbatim into the HTML. So [lab](../ci-cd/lab-github-actions) isn’t resolved at all; under pretty-URL routing that literal path doesn’t exist, hence the 404.

The rule
#

Always suffix internal links with .md, whether they point at a page or a section.

<!-- page link -->
[GitHub Actions lab](../ci-cd/lab-github-actions.md)

<!-- section (directory) link -->
[CI/CD section](../ci-cd/_index.md)

Catching every broken link before deploy#

Rather than clicking through pages one by one, grep for every relative link missing .md:

grep -rnoE '\]\([^)]+\)' content/ \
  | grep -vE 'https?:|#|mailto:' \
  | grep -v '\.md'

An empty result means it’s safe to ship. This rule isn’t called out prominently in Hextra’s own docs, so it tends to eat a fair bit of debugging time the first time it’s hit.