Hugo Architecture
Targets Hugo Extended 0.161 (Go-templated static-site generator). Theme styling integrates with ui-ux-architect; Go template syntax overlaps with go-architect; deploy pipelines follow ci-cd-architect. Concrete skeletons in RECIPES.md; pinned versions in STACK.md.
1. Project layout & content organization
- Standard top-level folders —
content/,layouts/,assets/,static/,data/,i18n/,archetypes/,themes/(if not module-mounted),hugo.toml. Skeleton in RECIPES § Project tree. content/mirrors the URL structure. Section folders (content/posts/,content/docs/) become URL prefixes; taxonomies are inferred from front matter, not folder names.assets/for processed files;static/for pass-through. Anything that needs fingerprinting, minification, transpilation, or image processing belongs inassets/and goes through Hugo Pipes. Truly static files (robots.txt,favicon.ico, prebuilt PDFs) go instatic/.data/for structured site data — JSON/YAML/TOML files queryable viasite.Data.<file>. Use for author lists, sponsor logos, redirect maps; do not use for content (that belongs incontent/).archetypes/definehugo newtemplates — one per content section, with sensible front-matter defaults.- One repository per site by default. Multi-site monorepos are an exception; reach for them only when ownership and deploy targets align.
2. Front matter conventions
- TOML front matter is the default (
+++delimiters). Matcheshugo.tomlconfig syntax — one parser to learn. YAML is acceptable for theme authors who must support broader ecosystems; pick one per repo and don't mix. - Required fields on every page —
title,date,draft(defaultfalseonce published). Drafts are excluded from production builds. - Taxonomies are arrays —
tags = ["x", "y"], never comma-separated strings. Taxonomies auto-generate listing pages. slugonly when the title is unstable. Otherwise let Hugo derive from the filename — stable URLs survive title edits.weightfor manual ordering — lower = earlier. Reserve for navigation menus and curated lists; chronological content usesdate.- Custom params under
[params]— never at the top level.paramsis the supported namespace for site-specific extensions; top-level keys collide with future Hugo additions.
3. Template hierarchy
Hugo's lookup order resolves templates from most-specific to most-generic. Internalize the order; don't memorize it — the Hugo template lookup docs are the source of truth.
baseof.htmlis the single shell template. Every other template extends it via{{ define "main" }}.single.htmlrenders one page;list.htmlrenders section/taxonomy listings;home.htmlis the site root.partials/are reusable fragments — header, footer, SEO meta. Pass an explicit context; never rely on the global scope.shortcodes/are content-callable partials — invoke from Markdown with{{< name >}}. Use for figures, callouts, embeds; do not use to inject styling.- Type/section overrides —
layouts/posts/single.htmlbeatslayouts/_default/single.html. The_default/folder is the fallback, not the convention.
Skeletons in RECIPES § Template hierarchy.
4. Hugo Modules over git submodules
- Themes and shared layouts ship as Hugo Modules — Go-module-backed, versioned via SemVer tags.
hugo mod getresolves;go.modrecords. - Why not git submodules? Submodules pin to commits with no version semantics, require
git submodule update --initafter every clone, and break on theme repo reorganizations. Modules give SemVer + automatic dependency resolution. hugo.toml [module]block declares imports, mounts, and replacements. Mount overrides let you patch a single template without forking the theme.- Vendor for reproducibility —
hugo mod vendorwrites_vendor/; commit it for hermetic builds (mirrors Go'svendor/discipline per go-architect).
Skeleton in RECIPES § Hugo Module setup.
5. Page Bundles over flat content
- Page Bundle =
index.md+ co-located assets in a folder.content/posts/launch-day/index.mdpluscover.jpg,diagram.svgin the same folder. - Two bundle types:
- Leaf bundle (
index.md) — a single page; resources are bundle-local. - Branch bundle (
_index.md) — a section page; child pages are independent.
- Leaf bundle (
- Why bundles? Page resources (
resources.Get,.Resources.GetMatch) are scoped to the bundle, image processing works on co-located files, and content + assets move together. - Flat
content/posts/foo.mdis acceptable for text-only posts with no images. Reach for bundles the moment you have a cover image or inline diagram.
6. Asset pipeline (Hugo Pipes)
Hugo Pipes is the built-in asset pipeline — no Webpack, no Vite. Extended edition required for Sass/SCSS.
- Source files in
assets/— invoke viaresources.Get "css/app.scss". - Standard chain —
toCSS(orjs.Build) →postCSS(optional, for Tailwind/autoprefixer) →minify→fingerprint→ render<link>/<script>withPermalink+Data.Integrity(SRI). - Fingerprinting is mandatory in production — long-cache headers + immutable URLs. Build with
--minifyand rely on the fingerprint for cache busting. - Image processing —
.Resize,.Fit,.Fill,.Filter. Pair withsrcsetfor responsive images. WebP/AVIF output via format conversion. Useq=for JPEG quality; don't blow the byte budget. - PostCSS lives outside Hugo —
postcss.config.js+package.json. Hugo invokes the binary; keep the toolchain pinned via repo-tooling-architect.
Skeleton in RECIPES § Asset pipeline chain.
7. Performance budget
- Build time target — under 10s for sites under 1k pages; under 60s for sites under 10k pages. Beyond that, profile (
hugo --templateMetrics) and audit the slowest partial/shortcode. - Per-page weight — under 100 KB transferred (HTML + CSS + JS + critical fonts) for content pages. Images load lazily via
loading="lazy"andsrcset. - No JS by default. Add JS only where it earns its place (search, comments, interactive widgets). Hugo's strength is shipping HTML; don't undermine it.
- Tailwind via PostCSS with
contentglobbing — production builds purge unused classes. Without purging, Tailwind ships ~3 MB CSS. - Critical CSS inline for above-the-fold when Lighthouse flags it; fingerprinted external CSS for the rest.
8. i18n & multilingual
[languages]block inhugo.toml— one entry per language, withweight,languageName,contentDir,languageDirection.- Translation strategies — by filename (
post.en.md+post.es.md) or by content directory (content/en/+content/es/). Pick one per site; filename mode is simpler, directory mode scales better past three languages. i18n/<lang>.tomlfor UI strings — invoke via{{ i18n "key" }}. Don't hardcode strings in templates.- Translation linking — Hugo auto-links translations by
translationKey(front matter) when filenames diverge. - Default language has no URL prefix unless
defaultContentLanguageInSubdir = true. Decide early — changing later breaks every existing URL.
9. Render hooks & Markdown extensions
- Goldmark is the Markdown parser. Render hooks override individual element rendering —
render-link.html,render-image.html,render-codeblock-<lang>.html,render-heading.html. - Use render hooks for — aut