Introduction
Hugo is one of the fastest and most flexible static site generators available today. However, to truly harness its power, you need to understand its configuration system and apply best practices. This guide will walk you through essential configuration settings and production-ready optimizations.
Essential Configuration
Base Configuration
Every Hugo site starts with a core configuration file. Here’s what you need to get started:
# hugo.toml
baseURL = 'https://yourdomain.com/'
title = 'Your Site Title'
defaultContentLanguage = 'en'
# Performance settings
enableRobotsTXT = true
enableGitInfo = false # Set true if using git for lastmod
enableEmoji = true # Optional
# Output formats
[outputs]
home = ['HTML', 'RSS', 'JSON']
section = ['HTML', 'RSS']
taxonomy = ['HTML', 'RSS']
term = ['HTML', 'RSS']
Build Configuration
Optimize your build process with these settings:
[build]
writeStats = true
noJSConfigInAssets = false
useResourceCacheWhen = 'fallback'
# Enable build stats for CSS purging
[build.buildStats]
enable = true
disableClasses = false
disableIDs = false
disableTags = false
Cache Busting
Ensure browsers always get the latest assets:
[[build.cachebusters]]
source = "assets/watching/hugo_stats\\.json"
target = "styles\\.css"
[[build.cachebusters]]
source = "(postcss|tailwind)\\.config\\.js"
target = "css"
[[build.cachebusters]]
source = "assets/.*\\.(js|ts|jsx|tsx)"
target = "js"
Performance Optimization
Image Optimization
Images often make up the bulk of a website’s bandwidth. Configure Hugo to optimize them automatically:
[imaging]
anchor = 'Smart' # Smart cropping
bgColor = '#ffffff'
hint = 'photo' # Options: photo, picture, drawing, icon, text
quality = 75 # Balance quality/size (75 is optimal)
resampleFilter = 'box' # Fast, good quality
Best Practices:
- Use WebP format for modern browsers
- Always specify dimensions to prevent layout shift
- Generate responsive images with different sizes
- Leverage Hugo’s image processing pipeline
Example template usage:
{{ $image := .Resources.Get "hero.jpg" }}
{{ $webp := $image.Resize "600x webp q75" }}
{{ $fallback := $image.Resize "600x jpg q75" }}
<picture>
<source srcset="{{ $webp.RelPermalink }}" type="image/webp">
<img src="{{ $fallback.RelPermalink }}" alt="{{ .Title }}" width="600" height="400">
</picture>
Minification
Reduce file sizes automatically:
[minify]
disableCSS = false
disableHTML = false
disableJS = false
disableJSON = false
disableSVG = false
disableXML = false
minifyOutput = true
[minify.tdewolff.html]
keepWhitespace = false
keepEndTags = true
keepDefaultAttrVals = true
keepDocumentTags = true
keepQuotes = false
[minify.tdewolff.css]
precision = 0
keepCSS2 = true
[minify.tdewolff.js]
precision = 0
keepVarNames = false
Production Build Command
Use these flags for optimal production builds:
hugo --gc --minify --cacheDir $TMPDIR/hugo_cache
Flags explained:
--gc: Run garbage collection to remove unused cache--minify: Minify HTML, CSS, JS, JSON, XML--cacheDir: Specify cache directory (useful for CI/CD)
Template Performance
Use partialCached for static content to improve build times:
{{/* Cache per page */}}
{{ partialCached "footer.html" . }}
{{/* Cache per section */}}
{{ partialCached "sidebar.html" . .Section }}
{{/* Multiple cache variants */}}
{{ partialCached "navigation.html" . .Lang .Section }}
Monitor your template performance:
hugo --templateMetrics --templateMetricsHints
This shows:
- Template execution times
- Cache hit rates
- Performance bottlenecks
SEO & Accessibility
Essential Meta Tags
Create a comprehensive SEO partial:
{{/* layouts/partials/seo.html */}}
{{/* Basic SEO */}}
<meta name="description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Site.Params.description }}{{ end }}">
<meta name="author" content="{{ .Site.Params.author }}">
<link rel="canonical" href="{{ .Permalink }}">
{{/* Open Graph */}}
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Site.Params.description }}{{ end }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
{{ with .Params.images }}
{{ range first 1 . }}
<meta property="og:image" content="{{ . | absURL }}">
{{ end }}
{{ end }}
{{/* Twitter Card */}}
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ .Title }}">
<meta name="twitter:description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Site.Params.description }}{{ end }}">
Sitemap Configuration
[sitemap]
changefreq = 'weekly'
filename = 'sitemap.xml'
priority = 0.5
Override per page in front matter:
---
title: "Important Page"
sitemap:
changefreq: daily
priority: 0.8
---
Accessibility Checklist
- ✅ All images have
altattributes - ✅ Use semantic HTML5 elements (
<nav>,<main>,<article>) - ✅ Proper heading hierarchy (h1 → h2 → h3)
- ✅ Sufficient color contrast (WCAG AA minimum)
- ✅ Keyboard navigation support
- ✅ ARIA labels where needed
- ✅ Skip to main content link
Security
Security Configuration
[security]
enableInlineShortcodes = false
[security.exec]
allow = ['^dart-sass-embedded$', '^go$', '^npx$', '^postcss$']
osEnv = ['(?i)^(PATH|PATHEXT|APPDATA|TMP|TEMP|TERM)$']
[security.funcs]
getenv = ['^HUGO_', '^CI$']
[security.http]
methods = ['(?i)GET|POST']
urls = ['.*']
Content Security Policy
Add to your base template:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;">
Security Headers
Configure in your hosting platform:
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
Asset Management
CSS/SCSS Pipeline
Process and optimize your stylesheets:
{{ $options := dict "targetPath" "css/main.css" "outputStyle" "compressed" }}
{{ $style := resources.Get "css/main.scss" | toCSS $options | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" integrity="{{ $style.Data.Integrity }}">
JavaScript Pipeline
Bundle and optimize JavaScript:
{{ $js := resources.Get "js/main.js" }}
{{ $js = $js | js.Build "main.js" | minify | fingerprint }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" defer></script>
Asset Versioning
Always use fingerprinting for cache busting:
{{ $asset := resources.Get "path/to/asset" | fingerprint }}
<link href="{{ $asset.RelPermalink }}">
This generates: main.abc123def456.css
Deployment
GitHub Pages Deployment
Create .github/workflows/hugo.yml:
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
defaults:
run:
shell: bash
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
extended: true
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Build with Hugo
env:
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: |
hugo \
--gc \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Monitoring & Maintenance
Build Performance
Monitor and optimize your build:
# Time the build
time hugo --gc --minify
# Check template performance
hugo --templateMetrics --templateMetricsHints
# Analyze build stats
hugo --debug --logLevel info
Pre-deployment Checklist
Create a testing script:
#!/bin/bash
set -e
echo "🔍 Running Hugo checks..."
# Build test
hugo --gc --minify --buildDrafts=false --buildFuture=false
# Link checking (requires htmltest)
htmltest
# HTML validation (requires html5validator)
html5validator --root public/
echo "✅ All checks passed!"
Content Organization
Directory Structure Best Practices
content/
├── authors/ # Separate taxonomy
├── en/ # Language separation
│ ├── _index.md
│ └── posts/
└── de/ # Language separation
├── _index.md
└── posts/
Front Matter Standards
Minimal required:
---
title: "Post Title"
date: 2025-11-21
draft: false
---
Recommended for SEO:
---
title: "Post Title"
description: "Clear, concise description for search engines"
date: 2025-11-21
lastmod: 2025-11-21
draft: false
slug: "custom-url-slug"
tags: ["tag1", "tag2"]
categories: ["category1"]
images: ["featured-image.jpg"]
author: "Your Name"
---
Quick Action Checklist
Immediate Actions
- ✅ Add
enableRobotsTXT = trueto config - ✅ Configure image optimization in
[imaging] - ✅ Enable
[build.buildStats] - ✅ Implement asset fingerprinting
- ✅ Set up GitHub Actions deployment
Short-term Actions
- ✅ Add minification configuration
- ✅ Configure sitemap settings
- ✅ Add security function restrictions
- ✅ Create automated testing script
Long-term Goals
- 📊 Set up performance monitoring
- 🚀 Implement advanced caching strategy
- 💡 Add Lighthouse CI
- 🌐 Configure CDN (if needed)
Conclusion
Hugo’s power lies in its flexibility and performance. By following these best practices and optimizing your configuration, you’ll build fast, secure, and SEO-friendly websites. In the next part of this series, we’ll dive deep into Hugo’s module system and advanced configuration patterns.
Resources
This is Part 1 of the Hugo Mastery series. Continue to Part 2: Module System & Advanced Configuration →