Hugo — Structure#
Layout pattern#
Custom — single-binary project with domain packages at root level.
Hugo does not follow standard Go Layout (no cmd/ directory). The single binary entry point is main.go at the repository root; all domain packages live as top-level directories. An internal/ directory exists for truly private infrastructure (WASM/JS bindings), and common/ groups shared utilities, but there is no pkg/ directory. The overall organization is by feature domain rather than by Go convention.
Directory map#
hugo/
├── main.go # Single entry point; delegates to commands.Execute()
├── magefile.go # Mage build system (build, test, install, codegen)
├── Dockerfile # Multi-stage Docker build; supports extended/withdeploy editions
│
├── commands/ # Cobra CLI command definitions (build, server, new, mod, deploy…)
├── common/ # Shared utility sub-packages (all prefixed h*)
│ ├── herrors/ # Error formatting with source context
│ ├── hexec/ # Safe external process execution
│ ├── hstrings/ # String helpers
│ ├── hsync/ # Sync primitives (cond vars, mutexes)
│ ├── htime/ # Time parsing/formatting
│ ├── loggers/ # Structured logging
│ ├── para/ # Parallel worker utilities
│ ├── paths/ # Path normalization
│ └── types/ # Shared value types
│
├── config/ # Configuration type hierarchy
│ ├── allconfig/ # Merged/resolved site config
│ ├── privacy/ # Privacy settings
│ ├── security/ # Security policy config
│ └── services/ # Third-party service config (Disqus, GA, etc.)
│
├── hugolib/ # Core site-building orchestration
│ ├── doctree/ # Radix-trie page tree
│ ├── filesystems/ # Virtual filesystem assembly
│ ├── pagesfromdata/ # Pages generated from data files
│ └── sitesmatrix/ # Multi-site / multilingual matrix
│
├── resources/ # Resource pipeline (pages, images, JS, CSS, fonts)
│ ├── page/ # Page type and collections
│ ├── images/ # Image processing (resize, crop, filter)
│ ├── resource/ # Base resource interface and registry
│ ├── resource_factories/ # Constructors for each resource type
│ └── resource_transformers/# Transform pipeline (babel, js, tocss, minifier, integrity…)
│
├── tpl/ # Template function library (~30 sub-packages by category)
│ ├── tplimpl/ # Template store and function registration
│ ├── tplimplinit/ # Init-time wiring of tplimpl
│ ├── collections/ # Slice/map operations for templates
│ ├── strings/ # String functions
│ ├── images/ # Image-related template functions
│ ├── js/ # JS bundling template functions
│ └── … # cast, compare, crypto, encoding, fmt, math, os, path, etc.
│
├── markup/ # Content converters
│ ├── converter/ # Converter interface and registry
│ ├── goldmark/ # Goldmark Markdown renderer (primary)
│ ├── asciidocext/ # AsciiDoc via external binary
│ ├── org/ # Org-mode via go-org
│ ├── pandoc/ rst/ # Pandoc and RST via external binaries
│ ├── highlight/ # Chroma syntax highlighting
│ └── tableofcontents/ # ToC extraction
│
├── hugofs/ # Filesystem abstraction (wraps afero)
│ ├── files/ # File classifier / component types
│ └── hglob/ # Glob matching on virtual FS
│
├── modules/ # Hugo Modules (Go-module-style theme/content imports)
│ └── npm/ # npm dependency management for Hugo modules
│
├── cache/ # Caching layers
│ ├── dynacache/ # Dynamic in-process cache with partition logic
│ ├── filecache/ # On-disk content/asset cache
│ └── httpcache/ # HTTP response cache
│
├── internal/ # Private infrastructure
│ ├── js/ # esbuild JS bundler integration (extended edition)
│ └── warpc/ # WASM RPC host (Dart Sass, KaTeX, WebP via WASM)
│
├── langs/ # Language / i18n support
│ └── i18n/ # Translation file loading and lookup
│
├── deploy/ # Cloud deployment (build-tag gated: withdeploy)
│ └── deployconfig/ # Deployment target config (S3, GCS, Azure)
│
├── output/ # Output format definitions (HTML, RSS, JSON, etc.)
├── media/ # MIME type registry
├── identity/ # Dependency identity / change tracking
├── parser/ # Front matter and page parsing
│ ├── metadecoders/ # TOML/YAML/JSON/CSV/XML decoder
│ └── pageparser/ # Page content + front matter parser
│
├── transform/ # Output HTML transforms (livereload inject, URL rewrite)
├── navigation/ # Menu construction
├── source/ # Source file abstraction
├── publisher/ # Final HTML output writer
├── watcher/ # File change watcher
│ └── filenotify/ # fsnotify wrapper
├── livereload/ # WebSocket live-reload server
├── related/ # Related content scoring
├── minifiers/ # HTML/CSS/JS minification
├── metrics/ # Build timing and performance counters
├── helpers/ # Legacy catch-all helpers (being gradually broken up)
├── compare/ # Deep equality and ordering
├── bufferpool/ # sync.Pool wrappers for byte buffers
├── deps/ # Central dependency container (Deps struct)
│
├── codegen/ # Source code generation utilities
├── docshelper/ # Generates JSON docs from Hugo internals
├── releaser/ # Release automation
├── htesting/ # Test helpers and quick-test matchers
│ └── hqt/ # qt-based test helpers
│
├── testscripts/ # txtar-based integration test scripts
└── docs/ # Hugo's own documentation site (self-hosted)Entry points#
| File | Binary | Description |
|---|---|---|
main.go | hugo | Single entry point — delegates to commands.Execute(os.Args[1:]) |
There is no cmd/ subdirectory. Hugo ships one binary. The commands/ package owns all Cobra command definitions: hugo (build), hugo server, hugo new, hugo mod, hugo deploy, hugo gen, hugo list, hugo convert, hugo env, hugo import, hugo release.
Package organization#
Internal packages (
internal/):internal/js— esbuild JavaScript bundler integration, used by the extended editioninternal/warpc— WASM RPC runtime for Dart Sass, KaTeX, and WebP processing without CGO
Public packages (
pkg/): None — Hugo does not use apkg/convention. All top-level directories are de-facto packages accessible within the module.Layering: Hugo uses a hub-and-spokes layering model rather than clean architecture or hexagonal:
deps/holds the centralDepsstruct that wires together configuration, filesystem, and services — it acts as a service locator / dependency container.hugolib/is the orchestrator; it imports almost everything else.resources/pageis the heaviest domain object, imported bytpl/,hugolib/, andcommands/.common/andbufferpool/are at the bottom — imported by nearly all other packages.tpl/depends onresources/andhugolib/but not vice-versa (template functions are consumers, not producers of core logic).- No strict layering enforcement; circular imports are prevented by convention and careful factoring (e.g.,
identity/is deliberately minimal to avoid cycles).
Build system#
- Build tool: Mage (
magefile.go) — Go-native build tool, no Makefile - Key targets:
mage hugo— build binary (default tags:none)mage install— install binarymage test— run full test suitemage testRace— tests with race detectormage generate— run codegen (page method stubs, docs helpers)- Build tags via
HUGO_BUILD_TAGSenv var:none|extended|withdeploy
- Three build editions:
none— standard Hugo, pure Go, no CGOextended— adds LibSass/Dart Sass (CSS processing), WebP image encoding; requires CGO or WASM fallbackwithdeploy— addsextended+ cloud deployment commands (AWS S3, GCS, Azure Blob)
- Docker: Yes, multi-stage. Stage
buildcross-compiles with CGO usingxxtoolchain; stagedart-sassfetches the Dart Sass binary; stagefinalassembles the runtime image with Node.js, npm, git, and Dart Sass.
Notable structural decisions#
Root-level binary, not
cmd/: The singlemain.goat the repo root is deliberately minimal (5 lines). This is practical for a single-binary tool but deviates from standard Go Layout, occasionally causing confusion for contributors.common/h*micro-package pattern: Every utility sub-package undercommon/uses anhprefix (herrors, hexec, hstrings, hsync…). This prevents shadowing stdlib names and signals internal provenance. The pattern produces ~18 small, focused packages instead of one largeutils/blob.Build-tag edition system: Three mutually-exclusive editions (
none/extended/withdeploy) are selected at compile time via build tags. This cleanly gates CGO dependencies (LibSass, libwebp) so the standard edition ships as a fully static binary.tpl/as a library of libraries: The ~30 sub-packages undertpl/each expose aNew()function returning a namespace struct;tpl/tplimplcollects them all and registers their methods into Go’stext/template. This design lets each function category evolve independently and be tested in isolation.internal/warpcWASM RPC: Rather than requiring CGO for Dart Sass or KaTeX, Hugo embeds a WASM runtime and communicates with compiled WASM modules via a custom RPC protocol. This enables the extended Sass features without CGO on platforms where CGO is unavailable, and is architecturally the most novel structural choice in the codebase.docs/as a Hugo site inside Hugo: The project’s own documentation site lives indocs/and is built with Hugo itself, providing a continuous integration check that real-world Hugo features keep working.testscripts/txtar integration tests: End-to-end build scenarios are expressed astxtarscripts (a Go test scripting format), providing readable, self-contained integration tests that exercise the full build pipeline without needing external fixtures.