Architecture specification

Static Websites

Each child of www/ is a self-contained site root whose content, layouts, assets, and configuration travel together and whose output is disposable.

Applies at
www/
Status
Stable
Source · managed
www/README.md

01 Defines

The home for static and content-driven websites: one directory per site under www/, each holding everything it needs to build, and each rendered into the single shared public/ output.

02 Applies when

  • A repository publishes generated static content — a Hugo site, a documentation site, a landing page.
  • A site’s primary output is files that can be uploaded and served as they are.
  • More than one site is published from the same repository.

03 Boundaries

  • Frontend applications with client-side state, routing, or their own build pipelines belong in app/, not www/.
  • Generated output is never a source; it is rebuilt from the site root.
  • Sites do not reach into each other’s layouts or themes through relative paths.

Expected behaviour

  1. 01
    Site content, layouts, assets, and configuration all live inside the site root.
  2. 02
    Generated site output is disposable and never committed.
  3. 03
    Shared layouts or assets move into an explicit shared location only once more than one site needs them.
  4. 04
    Sites are declared in HUGO_DIRS; the first builds into public/ and each additional site into public/<name>/.

Behaviour#

www/ is a logical grouping, not a site. Every child directory is a complete site root: point a static site generator at it and it builds, with nothing borrowed from a sibling. That keeps each site understandable on its own and lets a site be moved, renamed, or deleted without breaking another.

The make module for Hugo turns the declared sites into one output tree. The first site in HUGO_DIRS owns the root of public/; every later site is nested beneath it under its own directory name.

FlowFrom site roots to one output
  1. 01 Declare repository.mk lists the site roots in HUGO_DIRS Make Module Registries
  2. 02 Prepare prepare.hugo stages generated content, or prints a skip: Staged Content Mounts
  3. 03 Build hugo --minify --cleanDestinationDir per existing site root
  4. 04 Publish public/ is the one build output; link checking and deployment both read it Static Site Delivery

A declared site whose directory does not exist is skipped rather than failing the build, and when none exist the module says so with a skip: line.

www or app#

www/

  • Hugo-style sites and documentation sites
  • Landing pages and other static publishing targets
  • Output that is generated once and served as files

app/

  • SPAs and other app-style clients
  • Rich client-side state and routing
  • Build pipelines or deployment concerns beyond static publishing

Layout#

  • www/
  • README.md Owner documentation for the area Owner Documentation
  • <site>/ One self-contained site root
  • content/ Markdown with front matter
  • layouts/ Templates
  • assets/ Processed assets (CSS, JS)
  • static/ Copied to the output verbatim
  • hugo.yaml Site configuration
  • public/ Disposable build output, shared by every site
  • <second-site>/ Additional sites nest under their own name

Examples#

The build loop gives the first existing site the root of public/ and nests every other one:

scripts/build/52-hugo.mk
check.hugo: prepare.hugo ## Build Hugo sites into public/
	@existing=''; for site in $(HUGO_DIRS); do [ -d "$$site" ] || continue; existing="$$existing $$site"; done; \
	if [ -n "$$existing" ]; then set -e; first=1; for site in $$existing; do dest="$(REPO_ROOT)/public"; if [ $$first -eq 0 ]; then dest="$(REPO_ROOT)/public/$$(basename "$$site")"; fi; hugo --source "$$site" --destination "$$dest" --minify --cleanDestinationDir; first=0; done; else printf 'skip: no Hugo sites (directories not found)\n'; fi

Cleaning removes public/, any configured staging paths, and each site’s own public/ and .hugo_build.lock, so a clean build always starts from the site roots alone.