A static site is simple to publish, but simplicity does not remove the need for a release check. The useful checks are small enough to run on every release and specific enough to fail for a real reason.
Build a clean artifact
Use a pinned generator version and build into a disposable output directory:
set -eu
hugo version
hugo --cleanDestinationDir --gc --minify --destination public
--gc collects unused build-cache resources; it does not clean stale published pages. --cleanDestinationDir removes stale destination files, so use it only on the disposable artifact directory, never a directory containing source or unrelated data. Compare the printed version with the project’s pin; printing a version does not enforce it. Record the build inputs and verify the resulting artifact. A clean destination does not establish byte-for-byte reproducibility: timestamps and other nondeterministic inputs need separate control and comparison. Do not edit generated HTML by hand after the build.
Check the artifact, not only the source
Inspect the generated tree and verify that expected entry points exist. Run this assertion block as a standalone shell script; it must stop before printing the inventory if any required file is missing or empty:
set -eu
test -s public/index.html
test -s public/404.html
test -s public/robots.txt
test -s public/sitemap.xml
find public -type f -print | sort
Then search for accidental placeholders, local paths, and development-only hosts:
rg -l 'localhost|127\.0\.0\.1|TODO|example\.com|/Users/' public --glob '*.html'
This is a review aid, not an automatic release gate: examples like this checklist deliberately match, including in translated pages. This HTML-only scan does not cover XML feeds or JSON search output. rg exits 1 when there are no matches and 2 on an error. Review each listed file, distinguish fenced examples from active links or attributes, and use a parser-based link check for the actual gate. A private path in a published link is a release mistake.
Exercise the public routes
An isolated production-like server pointed at this exact artifact gives the strongest pre-release routing check. Hugo’s development server rebuilds content; the following is a separate source preview, not evidence that the already checked public/ bytes were served. Run the first command in one terminal and the requests in another:
hugo server --bind 127.0.0.1 --port 1313 --baseURL http://127.0.0.1:1313/ \
--disableFastRender --disableLiveReload --renderToMemory
curl -I http://127.0.0.1:1313/
curl -I http://127.0.0.1:1313/notes/
curl -I http://127.0.0.1:1313/resources/
curl -I http://127.0.0.1:1313/missing-page/
HEAD checks do not compare bodies. Repeat with GET against the staged server, then after publishing compare public bodies with the artifact and check both languages. Confirm that the missing route returns a 404 status in the production server. A pretty error page with a 200 status still breaks monitoring and caches.
Record the result
Keep the source commit, generator version, and checksum of each downloadable resource in the release record. This makes it possible to compare a live file with the source that produced it without relying on memory.
The downloadable version of this checklist is in the Resources section.
Sources
- Hugo command reference, generator flags for a clean production build, checked 2026-07-30.
- curl manual, HTTP verification and header inspection options, checked 2026-07-30.
- Static-site release checklist, downloadable companion resource.
- Hugo server command reference, development rebuilds, memory rendering, and live-reload controls, checked 2026-10-15.