This is the multi-page printable view of this section. .
Deployment
- 1: Serving your site locally
- 2: Deployment on GitHub Pages
- 3: Deployment on Cloudflare Pages
- 4: Deployment on Netlify
- 5: Deployment with Amazon S3 and CloudFront
OINK deployment has two separate stages: Hugo builds a complete public/
directory, then a static host publishes that directory. Keep build verification
and hosted verification distinct so a successful local command is not mistaken
for a completed production release.
Production build
Run the pinned Hugo Extended version from the site root:
hugo --gc --minify --cleanDestinationDir--gc removes unused cached resources, --minify produces production assets,
and --cleanDestinationDir removes files left by an earlier build. Review the
command before using the last option when publishDir points anywhere other
than the site’s dedicated output directory.
The build must finish without warnings that hide missing content, endpoints, or
resources. Inspect public/ locally before uploading it.
Local preview
For editing:
hugo server --disableFastRenderHugo’s development server proves that the source can render. It is not a production host and its live-reload behavior is not part of the generated site. Always run a clean production build before release.
Build environments and indexing
The plain hugo command uses the production environment. Oink marks HTML from
production builds as indexable and uses optimized, fingerprinted assets. For a
public preview that search engines must not index, build with another
environment:
hugo --environment preview --baseURL "https://preview.example.com/"Oink emits noindex, nofollow outside production. A hosting-level
X-Robots-Tag header is useful defense in depth, especially for non-HTML files.
Rebuild the reviewed source in production before publishing it at the
canonical URL; a preview artifact is not a production artifact.
Static hosting
Any host that can serve directories and files can publish OINK:
- object storage and a CDN;
- GitHub Pages, GitLab Pages, or similar Git-driven static hosting;
- Netlify, Cloudflare Pages, or another build-and-publish platform;
- an Nginx, Caddy, Apache, or internal file server.
Set baseURL to the canonical production URL. If the site is published below a
path such as https://example.com/manual/, include that path and test it;
OINK’s local assets and component URLs are designed to preserve subpath
deployments.
Cloudflare Pages
Connect Pages directly to the source branch. OINK does not require a GitHub Actions workflow that prebuilds and pushes an orphan Pages branch.
Use these settings for an Oink site:
| Setting | Value |
|---|---|
| Production branch | main, or the reviewed source branch |
| Root directory | the standalone site directory |
| Build command | hugo --gc --minify |
| Build output directory | public |
HUGO_VERSION |
0.164.0 |
SKIP_DEPENDENCY_INSTALL |
1 |
As of 2026-08-08, Cloudflare Pages’ v3 build image documents Hugo 0.147.7 as
its default, below OINK’s minimum 0.160.1. Set HUGO_VERSION explicitly for
both Production and Preview rather than relying on the moving platform default.
SKIP_DEPENDENCY_INSTALL=1 prevents the platform’s generic dependency installer
from adding a frontend installation step that the site does not need.
For previews that need the generated Pages URL as their canonical build URL:
hugo --gc --minify --baseURL "$CF_PAGES_URL"Cloudflare documents public as Hugo’s standard output directory, the
HUGO_VERSION override, and the CF_PAGES_URL base-URL pattern. Recheck the
platform documentation when changing the build image or pinned Hugo version.
See the Cloudflare Hugo guide and Cloudflare build image reference.
Air-gap deployment
For a disconnected environment, transfer both the site source and a verified theme archive rather than depending on an initial Hugo Module download:
- verify the theme archive’s sidecar SHA-256 file;
- install a supported Hugo Extended binary inside the environment;
- extract the theme into the site’s
themes/oink/directory; - set
theme: oinkand runhugo --gc --minifyin the site; - publish
public/to the internal static server.
Keep PlantUML and Diagrams.net disabled unless a reachable internal endpoint is configured. External links and embeds remain the content author’s responsibility.
Headers and caching
Fingerprint-bearing CSS and JavaScript can use long-lived immutable caching. HTML, search indexes, feeds, and sitemaps should use shorter caching or revalidation so a new deployment becomes visible promptly.
Hosts that recognize the _headers convention can use a site-owned
static/_headers file. This is not a portable standard; review security headers
against the site’s actual inline content and integrations.
Preview and production URLs
Canonical, hreflang, Open Graph, feeds, and absolute links depend on
baseURL. A production build should use the production URL; a preview may use
its temporary URL when link validation or social metadata needs to be accurate.
Do not publish a preview build to production without rebuilding against the canonical URL. Conversely, do not reject a preview merely because it contains the intentionally supplied preview host.
Deployment acceptance
Verify each layer independently:
Source and configuration
- the expected commit and pinned theme version are present;
baseURL, languages, menus, repository metadata, and optional endpoints are correct;- no unpublished draft or secret enters the public content tree.
Build artifact
- a clean production build succeeds with the pinned Hugo Extended version;
- English, Chinese, feeds, sitemaps, search indexes, and
404.htmlare present; - local assets resolve under both root and configured subpath;
- the artifact contains required license and attribution surfaces.
Hosted site
- the production URL returns the new artifact;
- canonical and language-alternate URLs use the production origin;
- navigation, search, language switching, dark mode, print, and representative components work in a real browser;
- redirects, custom headers, cache policy, and
404handling behave as configured; - an air-gap claim is backed by a browser network audit.
A green build log completes only the artifact stage. Deployment is complete after the hosted checks pass.
Rollback
Keep the previous known-good static artifact or hosting deployment identifier. If a new release fails hosted validation, restore that artifact first, then diagnose source or platform behavior. Rebuilding an old source commit with a new unpinned toolchain is not equivalent to restoring the original artifact.
1 - Serving your site locally
Depending on your deployment choice you may want to serve your site locally during development to preview content changes. To serve your site locally:
-
Ensure you have an up to date local copy of your site files cloned from your repo.
-
Ensure Hugo Extended and any source-fetch tools required by your chosen installation method are installed, as described in Prerequisites and installation. Node.js and PostCSS are not site-build prerequisites.
-
Run the
hugo servercommand in your site root. By default your site will be available at http://localhost:1313.
Now that you’re serving your site locally, Hugo will watch for changes to the content and automatically refresh your site. If you have more than one local git branch, when you switch between git branches the local website reflects the files in the current branch.
2 - Deployment on GitHub Pages
If your source is hosted on GitHub, GitHub Pages can build and publish the site with a single Actions workflow. The consuming site needs Hugo Extended but does not need Node.js, npm, PostCSS, or a generated deployment branch.
Project sites use a URL such as https://<OWNER>.github.io/<REPOSITORY>/; user
and organization sites use https://<OWNER>.github.io/. Custom domains are also
supported.
Prepare the repository
Push the complete site source to GitHub and confirm that this command succeeds from the repository root:
hugo --gc --minifySet the site’s baseURL to its production URL, or pass the Pages URL with
Hugo’s --baseURL option in the workflow. A project site must include the
repository path; otherwise CSS, JavaScript, and other resources will resolve
from the wrong location.
Add the Pages workflow
Create .github/workflows/pages.yml with the following contents. Keep
HUGO_VERSION aligned with a version validated by the theme.
name: Deploy Hugo site to Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
env:
GO_VERSION: 1.25.5
HUGO_VERSION: 0.164.0
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
submodules: recursive
- uses: actions/setup-go@v6
with:
go-version: ${{ env.GO_VERSION }}
- name: Install Hugo Extended
run: |
curl -L -o hugo.deb \
"https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb"
sudo dpkg -i hugo.deb
- uses: actions/configure-pages@v6
id: pages
- name: Build
run: >-
hugo --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/"
- uses: actions/upload-pages-artifact@v5
with:
path: public
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy
id: deployment
uses: actions/deploy-pages@v5If the theme is installed as a Git submodule, submodules: recursive checks it
out before Hugo runs. A complete offline archive can instead commit or restore
the site-owned themes/oink/ directory as part of the repository or build
input.
Enable GitHub Pages
In the repository settings, open Pages. Under Build and deployment, set
Source to GitHub Actions. Push the workflow to main, then follow its
first run in the repository’s Actions tab.
The workflow uploads only the generated public/ directory and publishes it
through the Pages deployment API. It does not maintain a gh-pages branch.
For other authentication, domain, and permission options, see GitHub’s Pages documentation and Hugo’s GitHub hosting guide.
3 - Deployment on Cloudflare Pages
Cloudflare Pages can build an Oink site from a connected GitHub or GitLab repository and create preview deployments for reviewed branches. The consumer build runs Hugo Extended directly and does not need a frontend package install.
Configure the project
Import the repository in Workers & Pages, select the production branch, and use these settings:
| Setting | Value |
|---|---|
| Production branch | main, or the reviewed source branch |
| Build command | hugo --gc --minify |
| Build output directory | public |
HUGO_VERSION |
0.164.0 |
SKIP_DEPENDENCY_INSTALL |
1 |
Set HUGO_VERSION in both the Production and Preview environments. Cloudflare
Pages’ v3 build image currently defaults to Hugo 0.147.7, which is below
Oink’s minimum 0.160.1. Pinning the validated version prevents a build-image
update from silently changing the toolchain. SKIP_DEPENDENCY_INSTALL=1
disables the generic dependency installation step that an Oink consumer does not
use.
If the Hugo site lives below the repository root, set Root directory to that directory. The output value is relative to the selected root.
Set the base URL
Production builds should use the site’s canonical custom domain in baseURL.
For a preview that needs its generated Pages URL in canonical and absolute
links, use Cloudflare’s deployment URL:
hugo --gc --minify --baseURL "$CF_PAGES_URL"Do not publish that preview artifact as production without rebuilding it for the canonical origin.
Deploy and verify
Save the configuration and inspect the first build log. A normal Oink consumer build should run Hugo without npm, PostCSS, Autoprefixer, or theme-owned CDN downloads. After deployment, verify:
- the
*.pages.devpreview or custom domain serves the expected commit; - English and translated routes use the intended canonical origin;
- search, language switching, dark mode, print, and representative components work;
- redirects, headers, custom domains, and
404behavior match the Pages project configuration.
Cloudflare Git integration and Direct Upload are different project modes. Check the current Pages documentation before choosing a mode that must later support an external deployment pipeline.
4 - Deployment on Netlify
Netlify can build a site from GitHub, GitLab, or Bitbucket and publish a preview for each pull request. An OINK consumer build runs Hugo Extended directly; it does not install Node.js packages or invoke PostCSS.
Configure the site
Push the complete source to your Git provider, import the repository in Netlify, and use these build settings:
| Setting | Value |
|---|---|
| Build command | hugo --gc --minify |
| Publish directory | public |
HUGO_VERSION |
0.164.0 or another theme-validated version |
If Netlify detects package manifests that exist only for theme-maintainer tooling, disable automatic dependency installation for the site. They are not part of the consumer build contract.
For a theme installed as a Git submodule, enable recursive submodule checkout.
For a Hugo module, Netlify also needs the normal Git and Go access required to
download the pinned module on a clean build. A complete offline distribution
uses the site-owned themes/oink/ directory and avoids that first-build
download.
Keep configuration in the repository
The same settings can be committed as netlify.toml:
[build]
command = "hugo --gc --minify"
publish = "public"
[build.environment]
HUGO_VERSION = "0.164.0"Keep production and deploy-preview contexts on the same Hugo version unless a preview is intentionally testing an upgrade. If preview builds need their generated URL as the base URL, add Netlify’s deploy URL to the Hugo command for that context.
To prevent a non-production deployment from being indexed, use a non-production Hugo environment as described in Build environments and indexing.
After saving the settings, trigger a deploy and inspect the build log. A normal consumer build should show one Hugo command and no npm, PostCSS, Autoprefixer, CDN download, or build-time remote-resource step.
5 - Deployment with Amazon S3 and CloudFront
There are several options for publishing your web site using Amazon Web Services. This section describes the most basic option, deploying your site using an S3 bucket and activating the CloudFront CDN (content delivery network) to speed up the delivery of your deployed contents.
-
After your registration at AWS, create your S3 bucket, connect it with your domain, and add it to the CloudFront CDN. This blog post has all the details and provides easy to follow step-by-step instructions for the whole procedure.
-
Download and install the latest version 2 of the AWS Command Line Interface (CLI). Then configure your CLI instance by issuing the command
aws configure(make sure you have your AWS Access Key ID and your AWS Secret Access Key at hand):$ aws configure AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY Default region name [None]: eu-central-1 Default output format [None]: -
Check the proper configuration of your AWS CLI by issuing the command
aws s3 ls, this should output a list of your S3 bucket(s).
-
Inside your
hugo.toml/hugo.yaml/hugo.json, add a[deployment]section like this one:[deployment] [[deployment.targets]] name = "aws" URL = "s3://www.your-domain.tld" cloudFrontDistributionID = "E9RZ8T1EXAMPLEID"deployment: targets: - name: aws URL: 's3://www.your-domain.tld' cloudFrontDistributionID: E9RZ8T1EXAMPLEID{ "deployment": { "targets": [ { "name": "aws", "URL": "s3://www.your-domain.tld", "cloudFrontDistributionID": "E9RZ8T1EXAMPLEID" } ] } }
-
Run the command
hugo --gc --minifyto render the site’s assets into thepublic/directory of your Hugo build environment. -
Use Hugo’s built-in
deploycommand to deploy the site to S3:hugo deploy Deploying to target "aws" (www.your-domain.tld) Identified 77 file(s) to upload, totaling 5.3 MB, and 0 file(s) to delete. Success! Invalidating CloudFront CDN... Success!As you can see, issuing the
hugo deploycommand automatically invalidates your CloudFront CDN cache. -
That’s all you need to do! From now on, you can easily deploy to your S3 bucket using Hugo’s built-in
deploycommand!
For more information about the Hugo deploy command, including command line
options, see this synopsis. In
particular, you may find the --maxDeletes int option or the --force option
(which forces upload of all files) useful.
If the source of your site lives in a GitHub repository, you can use GitHub Actions to deploy the site to your S3 bucket as soon as you commit changes to your GitHub repo. Setup of this workflow is described in this blog post.
If S3 does not meet your needs, consider AWS Amplify Console. This is a more advanced continuous deployment (CD) platform with built-in support for the Hugo static site generator. A starter can be found in Hugo’s official docs.