Deploy Hugo Static Sites with DeployHQ
Prerequisites:
- A server with SSH or SFTP access (VPS, dedicated, or shared hosting)
- A Hugo project in a Git repository
- A DeployHQ account
What is Hugo?
Hugo is a static site generator written in Go. It's the fastest SSG available — building thousands of pages in under a second — and ships as a single binary with zero dependencies. No Node.js runtime, no Ruby, no Python. Just download the binary and run it.
Hugo powers documentation sites, blogs, marketing pages, and portfolios. Its templating system is based on Go's html/template package, and it supports content organisation through taxonomies, sections, and archetypes.
Hugo has over 80,000 GitHub stars and a mature ecosystem of themes and modules.
Step 1: Install Hugo
macOS (Homebrew):
bash
brew install hugo
Ubuntu/Debian:
bash
sudo apt install hugo
Binary download (any platform): ```bash
Download the extended version (includes SCSS support)
curl -sL https://github.com/gohugoio/hugo/releases/download/v0.145.0/hugo_extended_0.145.0_linux-amd64.tar.gz | tar xz sudo mv hugo /usr/local/bin/ ```
Always use the extended version. The standard version lacks SCSS/SASS compilation, which most themes require.
Verify installation: ```bash hugo version
hugo v0.145.0-extended ...
## Step 2: Create a Hugo Site
```bash
hugo new site my-site
cd my-site
Add a theme (most Hugo sites use one):
bash
git init
git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke themes/ananke
Configure the theme in hugo.toml:
toml
baseURL = 'https://example.com/'
languageCode = 'en-gb'
title = 'My Site'
theme = 'ananke'
Create your first post:
bash
hugo new content posts/my-first-post.md
Start the development server:
bash
hugo server -D
The site is available at http://localhost:1313 with live reload.
Step 3: Project Structure
my-site/
├── archetypes/ # Content templates for hugo new
│ └── default.md
├── assets/ # Files processed by Hugo Pipes (SCSS, JS)
├── content/ # Markdown content files
│ └── posts/
│ └── my-first-post.md
├── data/ # Data files (JSON, YAML, TOML)
├── i18n/ # Translation strings
├── layouts/ # Template files
│ ├── _default/
│ │ ├── baseof.html
│ │ ├── list.html
│ │ └── single.html
│ └── partials/
├── static/ # Static files copied as-is (favicon, robots.txt)
├── themes/ # Theme directory (usually Git submodules)
│ └── ananke/
├── hugo.toml # Site configuration
└── go.mod # Hugo module dependencies (optional)
Key Directories
- content/ — Markdown files with YAML/TOML front matter. Directory structure maps to URL structure.
- layouts/ — Go templates. Override theme templates by placing files with the same path here.
- assets/ — Files that Hugo processes (SCSS compilation, image resizing, JS bundling).
- static/ — Files copied verbatim to
public/. Use for favicons,robots.txt, pre-built assets. - themes/ — Installed themes. Typically Git submodules.
Step 4: Configuration
Hugo supports hugo.toml, hugo.yaml, or hugo.json. TOML is the convention.
baseURL = "https://example.com/"
languageCode = "en-gb"
title = "My Hugo Site"
theme = "ananke"
[params]
description = "A Hugo site deployed with DeployHQ"
author = "Your Name"
[markup]
[markup.goldmark]
[markup.goldmark.renderer]
unsafe = true # Allow raw HTML in markdown
[outputs]
home = ["HTML", "RSS", "JSON"] # Enable JSON for search
[minify]
disableCSS = false
disableHTML = false
disableJS = false
disableJSON = false
disableSVG = false
disableXML = false
Environment-Specific Configuration
Hugo supports configuration directories for per-environment settings:
config/
├── _default/
│ └── hugo.toml # Base configuration
├── production/
│ └── hugo.toml # Production overrides
└── staging/
└── hugo.toml # Staging overrides
Build with a specific environment:
bash
hugo --minify --environment production
Step 5: Core Features
Content Management
Hugo content uses front matter for metadata:
---
title: "My Post Title"
date: 2026-03-07
draft: false
tags: ["deployment", "hugo"]
categories: ["tutorials"]
description: "A brief description for SEO"
---
Post content in Markdown here.
Taxonomies
Hugo supports taxonomies (tags, categories, or custom):
[taxonomies]
tag = "tags"
category = "categories"
series = "series"
Shortcodes
Reusable content snippets:
{{< youtube dQw4w9WgXcQ >}}
{{< figure src="/images/photo.jpg" caption="A photo" >}}
Hugo Pipes (Asset Processing)
Process SCSS, fingerprint assets, and minify in templates:
{{ $style := resources.Get "scss/main.scss" | toCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" integrity="{{ $style.Data.Integrity }}">
Image Processing
Hugo can resize and convert images at build time:
{{ $image := resources.Get "images/hero.jpg" }}
{{ $small := $image.Resize "600x webp" }}
<img src="{{ $small.RelPermalink }}" alt="Hero" width="{{ $small.Width }}" height="{{ $small.Height }}">
Multilingual Support
defaultContentLanguage = "en"
[languages]
[languages.en]
title = "My Site"
weight = 1
[languages.fr]
title = "Mon Site"
weight = 2
Content is organised per-language: content/en/posts/ and content/fr/posts/.
Step 6: Build for Production
hugo --minify
Output goes to public/:
public/
├── index.html
├── index.xml # RSS feed
├── sitemap.xml
├── posts/
│ ├── index.html # List page
│ └── my-first-post/
│ └── index.html # Single page
├── tags/
├── categories/
├── css/
├── js/
└── images/
Hugo generates clean URLs by default: /posts/my-first-post/ serves posts/my-first-post/index.html.
Build statistics:
bash
hugo --minify --printPathWarnings --printUnusedTemplates
Step 7: Deploy with DeployHQ
Create a DeployHQ Project
- Sign up at deployhq.com
- Create a new project and connect your Git repository
- DeployHQ automatically installs a webhook for push-triggered deployments
Configure the Build Command
Hugo is a Go binary, not a Node.js package. The build command needs to download Hugo on the build server:
cd %path% && curl -sL https://github.com/gohugoio/hugo/releases/download/v0.145.0/hugo_extended_0.145.0_linux-amd64.tar.gz | tar xz && ./hugo --minify
Important: Use hugo_extended if your theme uses SCSS. The standard version will fail silently or with a cryptic error.
Pin the Hugo version. Hugo occasionally introduces breaking changes. Update the version in your build command deliberately, not automatically.
Set the Deployment Subdirectory
public
This ensures only the built static files are deployed — not your Hugo source code, themes, or content markdown.
Configure Your Server
- Protocol: SSH (recommended) or SFTP
- Hostname: Your server IP or domain
- Deployment Path:
/var/www/hugo-site/ - Authentication: SSH key
Git Submodules for Themes
DeployHQ supports recursive submodule checkout. If your theme is a Git submodule, it's cloned automatically during deployment. No extra configuration needed.
Verify your .gitmodules file is committed:
ini
[submodule "themes/ananke"]
path = themes/ananke
url = https://github.com/theNewDynamic/gohugo-theme-ananke.git
Server Configuration (Nginx)
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/hugo-site;
index index.html;
# Static assets
location ~* \.(css|js|png|jpg|jpeg|gif|svg|ico|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# HTML pages
location / {
try_files $uri $uri/ $uri/index.html =404;
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
error_page 404 /404.html;
}
No PM2 or process manager needed — Hugo sites are pure static files.
Branch-Based Environments
| Branch | Server | Build Flag |
|---|---|---|
main |
production | ./hugo --minify --environment production |
staging |
staging | ./hugo --minify --environment staging --baseURL https://staging.example.com/ |
Deploy
Push a commit. DeployHQ:
1. Clones your repo (with theme submodules)
2. Downloads Hugo binary and builds the site
3. Compares public/ against what's on the server
4. Transfers only the changed files via SSH/SFTP
Edit one blog post? Hugo rebuilds in milliseconds. DeployHQ transfers ~3-4 files (the post, the list page, RSS feed, sitemap). Deployment completes in seconds.
Step 8: Troubleshooting
"TOCSS: ... this feature is not available in your current Hugo version"
You're using the standard Hugo binary instead of the extended version. Update your build command to download hugo_extended:
curl -sL https://github.com/gohugoio/hugo/releases/download/v0.145.0/hugo_extended_0.145.0_linux-amd64.tar.gz | tar xz
Theme Not Found
Ensure the theme is either:
- A Git submodule (check .gitmodules is committed)
- Or committed directly in the themes/ directory
If using submodules, verify the URL in .gitmodules is accessible from DeployHQ's build server.
Wrong baseURL in Production
Links and assets point to localhost or the wrong domain. Set the correct baseURL in hugo.toml or override it in the build command:
./hugo --minify --baseURL "https://example.com/"
Build Works Locally But Fails on DeployHQ
Check Hugo version mismatch. Your local Hugo might be newer or older than the version in the build command. Pin the same version in both.
Also check for OS-specific issues — if you develop on macOS but deploy from Linux, ensure your theme doesn't use case-sensitive file paths incorrectly.
Submodule Cloning Fails
If the theme repository is private, the DeployHQ SSH key needs access to both your main repo and the theme repo. Either:
- Make the theme repo public
- Add the DeployHQ key to the theme repo as a deploy key
- Use HTTPS with embedded credentials in .gitmodules
Conclusion
Hugo's build speed is legendary, and pairing it with DeployHQ's differential deployment means your content goes live seconds after pushing. The public/ directory contains pure static files — no server runtime, no process manager, no database. Just HTML, CSS, and JavaScript served by Nginx.
For other frameworks, browse the full DeployHQ guides library.
Ready to automate your Hugo deployments? Sign up for DeployHQ — it's free for one project.
Need help? Contact us at support@deployhq.com or on Twitter/X.