Your local hugo build works, but GitHub Actions fails randomly. Classic.
The root cause is usually not the workflow syntax. It is environment drift, missing permissions, and unstable dependencies.
This guide gives you a stable Hugo deployment workflow for GitHub Pages: pinned versions, minimum required permissions, and actionable failure signals.
1) Deployment rules first
A reliable pipeline should guarantee:
- Auto build and publish on every push
- Fixed toolchain versions
- Fast failure with readable logs
2) Recommended workflow (copy and run)
Create .github/workflows/deploy-hugo.yml:
name: Deploy Hugo
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: "0.145.0"
TZ: "Asia/Shanghai"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: ${{ env.HUGO_VERSION }}
extended: true
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
- name: Build
run: hugo --minify --gc
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
3) Why this setup is robust
Pin Hugo version
Never rely on runner defaults. Theme and template behavior can break across versions.
Explicit Pages permissions
pages: write and id-token: write are both required for deployment.
Concurrency guard
If multiple pushes happen quickly, old runs are canceled to prevent stale deploys.
Recursive submodule checkout
If your theme is a submodule, missing recursive checkout will break builds.
4) Top 5 common failures
Error: Failed to create deployment
Check:
- Repository Settings → Pages → Source is GitHub Actions
- Workflow includes
pages: writeandid-token: write
hugo: command not found
Check:
actions-hugostep actually ranhugo-versionis valid
module not found or theme render errors
Check:
submodules: recursiveis enabled- Local and CI Hugo versions match
No files were found with the provided path: ./public
Check:
- Hugo build really outputs to
public/ - Config errors did not stop build early
Deploy succeeds but styles are broken
Check:
baseURLmatches your Pages domain- No hardcoded absolute asset paths
5) Add a quick sanity check
Append this after build:
- name: Sanity check
run: |
test -f public/index.html
echo "Build output looks good"
Simple, but effective against “green build, empty output” mistakes.
6) Summary
For stable Hugo deployment, focus on four things:
- Pin versions
- Set correct permissions
- Pull complete dependencies
- Keep logs readable for troubleshooting
Get these right and your CI will be more reliable than most blog pipelines.