Cloudflare Pages with Hugo -- Deploy Static Sites
In this tutorial, you'll learn about Cloudflare Pages with Hugo. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Cloudflare Pages is a JAMstack hosting platform that integrates with Hugo static site generators, providing automatic builds from Git repositories, global edge deployment, custom domains, and built-in performance features for documentation sites, blogs, and marketing pages.
Why Cloudflare Pages for Hugo
Hugo is one of the fastest static site generators, building thousands of pages in seconds. Cloudflare Pages takes the output and deploys it to Cloudflare's global edge network, serving every page from 330+ locations worldwide. Unlike traditional hosting that serves all traffic from a single origin, Pages delivers each request from the nearest edge node with instant cache warming. The platform integrates directly with Git -- push to your Repository, and Pages automatically builds, deploys, and versions your site. Each commit gets a unique preview URL for review before production deployment. Compared to Cloudflare's Workers which are for Serverless compute, Pages specializes in static asset hosting with optional Serverless Functions for dynamic features. For Hugo sites, this means lightning-fast load times, automatic HTTPS, and no server management. The combination of Hugo's build speed and Pages' edge delivery rivals or exceeds Netlify and Vercel for static sites.
Real-world use: A technical documentation site with 5000+ pages builds with Hugo in under 15 seconds. Cloudflare Pages deploys the output globally, and readers in India, Brazil, and Germany all see sub-100ms load times because content is served from their nearest edge locations.
Hugo Pages Architecture
flowchart LR
G[Git Push] --> A[Cloudflare Pages Build]
A --> H[Hugo Build]
H --> S[Static Output]
S --> D[Deploy to Edge]
D --> E1[Edge Node US]
D --> E2[Edge Node EU]
D --> E3[Edge Node Asia]
D --> E4[Edge Node Oceania]
E1 --> U1[User Request]
E2 --> U2
E3 --> U3
subgraph Build_Process
I[Install Hugo] --> B[hugo --minify]
B --> O[public/ directory]
end
style A fill:#f90,color:#fff
style D fill:#3498db,color:#fff
style O fill:#2ecc71,color:#fff
When you push to Git, Cloudflare Pages clones the Repository, runs the Hugo build command, and deploys the public/ output directory to the edge. The entire Process typically completes in under 30 seconds for most Hugo sites.
Setting Up Hugo for Pages
# Step 1: Create a Hugo site
hugo new site my-docs-site
cd my-docs-site
# Step 2: Add a theme (as a git submodule)
git init
git submodule add https://github.com/alex-shpak/hugo-book themes/book
# Step 3: Configure for Pages compatibility
echo 'baseURL = "https://your-domain.com"
languageCode = "en-us"
title = "My Documentation"
theme = "book"
[outputs]
home = ["HTML"]
page = ["HTML"]
section = ["HTML"]
[module]
[[module.mounts]]
source = "content"
target = "content"' > hugo.toml
# Step 4: Create your first content
hugo new content/_index.md
hugo new content/getting-started/_index.md
# Expected output:
# Your site builds successfully with "hugo" command
# Output directory: ./public/
# Step 5: Create the Pages build configuration
echo '[build]
command = "hugo --minify"
publish = "public"
[build.environment]
HUGO_VERSION = "0.128.0"' > .pages.yml
# Or configure directly in the Cloudflare Dashboard:
# Build command: hugo --minify
# Build output directory: public
# Environment variables: HUGO_VERSION = 0.128.0
Cloudflare Pages automatically detects Hugo projects. If you have a hugo.toml or config.toml in the Repository root, Pages uses the default Hugo build command. Set HUGO_VERSION in environment variables to pin a specific version.
Deploying from GitHub
# .github/workflows/pages.yml (optional -- Pages integrates directly)
# Cloudflare Pages natively connects to GitHub, so this is often unnecessary.
# Push to the connected branch and Pages auto-deploys.
# For manual deployment via Wrangler:
# Install Wrangler
npm install -g wrangler
# Login to Cloudflare
npx wrangler login
# Deploy Hugo site to Pages
npx wrangler pages deploy public/ --project-name=my-hugo-site
# Expected output:
# ✨ Deploying project "my-hugo-site"
# Uploading... (34 files, 2.3 MB)
# ✨ Deployment complete! Take a peek at:
# https://my-hugo-site.pages.dev
#
# To deploy to a custom domain, add it in the Cloudflare Dashboard.
The simplest deployment workflow is connecting your Git Repository in the Cloudflare Dashboard. Every push to the production branch triggers a build and deploy. Wrangler CLI deployment is useful for CI/CD pipelines or deployments from non-Git sources.
Adding Pages Functions for Dynamic Content
// functions/search.js -- Serverless search for Hugo docs
export async function onRequest(context) {
const { request, env } = context;
const url = new URL(request.url);
const query = url.searchParams.get('q');
if (!query) {
return new Response('Missing search query', { status: 400 });
}
// Search from D1 (populated during build or via a cron)
const { results } = await env.DB.prepare(
`SELECT title, path, excerpt FROM pages
WHERE title LIKE ?1 OR content LIKE ?1
LIMIT 20`
).bind(`%${query}%`).all();
return new Response(JSON.stringify(results), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, max-age=60'
}
});
}
// Expected behavior:
// GET /search?q=cloudflare -> JSON array of matching pages
// Response cached at edge for 60 seconds
// Queries D1 database populated with Hugo page content
Pages Functions add Serverless logic alongside your Hugo static output. Files in the functions/ directory become Serverless endpoints. This pattern adds search, contact forms, authentication, or API proxies to an otherwise static Hugo site without running a separate backend.
Common Errors
| Error | Cause | Fix |
|---|---|---|
Build failed: command not found: hugo |
Hugo not installed in the build environment | Set HUGO_VERSION environment variable in Pages build settings |
Build output directory "public" not found |
Hugo outputs to a different directory | Verify publishDir in your hugo.toml matches the Pages publish setting |
Page not found |
Wrong baseURL in Hugo config | Set baseURL to your actual domain or leave empty for relative URLs |
Preview deployment broken |
Absolute URLs pointing to localhost | Use relative URLs or set baseURL based on the CF_PAGES_URL environment variable |
Git submodule not initialized |
Theme or dependency submodules not fetched | Ensure submodules are public or add an SSH deploy key with submodule access |
Practice Questions
- What build command and output directory does Cloudflare Pages use for Hugo sites?
- How do you pin a specific Hugo version for Pages builds?
- How can you add dynamic Serverless functionality to a Hugo site on Pages?
FAQ
Summary
Cloudflare Pages provides seamless deployment for Hugo static sites with automatic Git-based builds, global edge distribution, and built-in performance optimizations. Configure your Hugo site with a pinned HUGO_VERSION, set the build command to hugo --minify, and point the output to public/. Add Pages Functions for dynamic features like search, contact forms, or authentication. Each deployment gets a unique preview URL for review before production. Cloudflare Pages is the platform powering DodaTech's own documentation site at tutorials.dodatech.com, delivering instant load times to readers worldwide.
This guide is brought to you by the developers of Cloudflare, Hugo static site generator, and Durga Antivirus Pro at DodaTech.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro