Cross-references
Pointing a reader at another page sounds like one problem. It is three, and for a while this site solved it four different ways — a front matter list on one post, hand-typed “Companion note:” lines on four others, an arrow in the data tables, and ad-hoc “See also” prose wherever I happened to want one. Nothing enforced consistency, so nothing was consistent.
There are now three mechanisms, chosen by what the pointer is for.
| Mechanism | Where it appears | Use it when |
|---|---|---|
related: front matter | End of page, as a list | Several pages are relevant; no explanation needed |
{{< companion >}} | Top of page, with a sentence | One page gives essential context for this one |
backLink in a data file | Inside a table row, as ↩︎ | A table row has a matching note |
related: — the end-of-page list#
A list of paths in front matter renders a Related posts block after the content.
related:
- /docs/site-implementation/shortcodes/callouts/
- /docs/site-governance/content/markdown/Paths are language-agnostic. Each language site resolves them against its own pages, so the identical list goes in both the .en.md and .fr.md front matter — which is the point, because the previous hand-maintained version existed only in English and the French pages silently rendered nothing.
Two things it does deliberately:
It renders every entry. An earlier version capped the list at three, silently. The post that hit the cap had four, and the hidden fourth turned out to point at a page that did not exist — so the truncation was concealing a broken link.
It warns on unresolvable paths at build time. Note that a draft: true page does not resolve, so pointing at an unpublished draft is reported as missing rather than failing quietly.
companion — the top-of-page pointer#
Sometimes the reader needs a page before this one, and needs to know why. That is not a list; the sentence is the value.
{{< companion "/blog/rustdesk/self-hosting/" >}}
explains the architecture and server-side tradeoffs behind this install runbook.
{{< /companion >}}It renders as a quiet ↩︎ aside above the content: the label, the linked page title, then your sentence. The install runbooks use it to point back at the architecture post, so each runbook stays a runbook instead of re-explaining the design.
Hugo resolves the path at build time and fails the build on a bad one — a typo is caught immediately rather than shipping as a dead link.
backLink — the table arrow#
The /uses, /projects and /publications pages are built from YAML, and a table row has no room for prose. A backLink on an entry adds a superscript ↩︎ after the name, linking to the related note:
- name: chezmoi
backLink: /til/chezmoi/The rule#
Two rules keep these from sprawling again.
Cross-references are navigation, not severity. They stay visually quiet — no fill, no colour. Callouts are the loud mechanism, reserved for content that changes what the reader should do. A companion note dressed as a warning devalues real warnings.
↩︎ always means “related content.” It is the shared glyph across companion notes and table rows, so the same mark means the same thing everywhere it appears.
One case deliberately stays plain prose: a line pointing at external sources is a citation, not a cross-reference, and belongs in the text where the reader can see what they are clicking.