Chrome build modes
A docs site re-emits the same auto-generated chrome — the navbar, footer, and left-nav — on every page, even though those regions are usually identical site-wide. That repetition slows the build, bloats the output, and slows anything that processes every page, such as a link checker; it also makes for noisy output diffs.
Use the td.chrome parameter to select one of two build modes:
full(default) emits each page’s chrome on the page itself, ready for any client. Anytd.chromevalue other thansharedis treated asfull, so a typo fails safe.sharedemits each region on just one donor page per locale and restores it on the other pages in the browser with a small script. The output stays lean, while readers still get the full navigation once the page loads.
shared mode is in the spirit of the app-shell pattern but
applied to page chrome, where a single region instance is fetched from its
donor and restored on the client, over an otherwise static multi-page
site.
The shared mode helps wherever a JavaScript-capable client or a link checker
consumes the output:
- Faster link checking. A checker reaches each unique chrome link once instead of once per page, and sees the lean output because it doesn’t run the restore script.
- Cleaner output diffs. A change to a shared region shows up once instead of on every page, so a diff surfaces the content that actually changed.
- Smaller output for local development and deploy previews.
What shared mode keeps reachable
In shared mode, each region stays on exactly one page per locale — its
donor, which the browser restores the others from — so every chrome link
stays reachable without JavaScript:
- Navbar and footer: kept on each locale’s home page. Their links are config-defined and identical across the locale, except for the navbar’s optional language selector and version menu — see the caution.
- Left-nav (computed per page): kept on each locale’s docs landing page; it
carries the full docs tree. On a doc-rooted site, that landing
page is the home page.
sharedmode currently targets the docs section; other sections (such as blog) aren’t a validated target yet, so keepfullfor them.
The navbar’s language selector points to each page’s own translation rather than a fixed target, but those translations are docs pages that the destination locale’s left-nav already covers, so the single kept navbar loses no reachable link.
shared mode is an experimental optimization that rests on assumptions
about how chrome repeats, which may not hold for every site. The browser
restore of the navbar’s language and version selectors is still a work in
progress, so today shared is best suited to development, deploy previews,
link-checking, and output-diffing builds rather than production deploys:
clients without JavaScript (and some search crawlers) see only the donor
pages’ chrome. Keep full for production, and run full-site link checks as
well, even if less often.
Two known cases:
- A navbar version menu with
version_menu_pagelinksenabled emits per-page links that the single kept navbar won’t cover yet. - A scoped sidebar (
sidebar_root_for) restores the right links and active state, but its re-rooted subtree can differ structurally from a full build (an extra wrapper element, deeperulnesting). The difference isn’t visible in the rendered nav — only in a serialized-HTML diff.
Setting the build mode
Set the td.chrome parameter to shared (the default is full):
params:
td:
chrome: shared
[params.td]
chrome = "shared"
For a link-checking or preview CI job, it’s usually cleaner to set it through the environment instead, leaving your committed config untouched:
HUGO_PARAMS_TD_CHROME=shared hugo
See Hugo’s configuration with environment variables. Then run
your link checker against the generated public/ output as usual: a shared
build needs no checker-specific configuration, since the donor pages keep every
chrome link reachable.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.