Shipping a Hugo site on Cloudflare Pages without the headache
Putting a static site online stopped being a project. What still eats time is the first half hour — the one between “works on my machine” and “works in production, with HTTPS and automatic deploys”.
Here is the path I use today.
The minimum contract
Cloudflare Pages needs three things: a Git repository, a build command and an output directory. For Hugo:
# Build command
hugo --gc --minify
# Build output directory
publicThe rest is environment configuration. And that is where almost every first deploy fails.
Trap 1: the Hugo version
The Pages runner does not use the version you have locally. Without pinning, you get an old one — usually without the extended build, which breaks any theme that touches SCSS.
Set the environment variable in the project settings:
HUGO_VERSION = 0.165.0Pin the version in the repository too, in a file people can actually read. An invisible environment variable is technical debt waiting to happen.
Trap 2: Hugo Modules need Go
If the theme ships as a Hugo Module — and most do now — the runner needs Go
available before hugo runs:
GO_VERSION = 1.27.1Without it the build dies with a module not found that says nothing about
the actual cause.
Trap 3: baseURL and previews
Every branch gets its own preview URL. If baseURL is hardcoded in the
config, the preview’s absolute links point at production. The fix is to let
Pages inject the value:
hugo --gc --minify --baseURL "$CF_PAGES_URL"In production CF_PAGES_URL is the final domain, so one command covers both
cases with no branching.
What you get for free
After that, every git push to main is a deploy. Branches become previews.
The certificate is issued and renewed on its own. And the cost stays at zero
up to traffic most personal blogs will never see.
The official docs live at developers.cloudflare.com/pages, and the build configuration section is worth reading before the first deploy.