Hugo on Windows Runbook & Cheatsheet
Hugo on Windows Runbook & Cheatsheet
Hugo builds a static site from Markdown in milliseconds — a single Go binary, no runtime, no database. This walks a Windows setup end to end in PowerShell: install, new site, theme, content, config, build, deploy; then the reference for CLI, front matter, templates, and shortcodes.
Install
# winget (Microsoft's package manager) - preferred winget install -e --id Hugo.Hugo.Extended winget install -e --id Git.Git # Alternatives # scoop install hugo-extended # choco install hugo-extended # Open a NEW terminal so PATH refreshes, then: hugo version
No “+extended” in the output? You installed the plain edition. Uninstall it and reinstall Hugo.Hugo.Extended, otherwise Sass-based themes will not build.
| Tool | Install when |
|---|---|
| Dart Sass | Your theme uses modern Sass syntax; winget install -e –id Sass.DartSass. |
| Go | You will use Hugo Modules for themes; winget install -e –id GoLang.Go. |
| VS Code | Editing content and templates comfortably. |
Create a site
cd $HOME\sites hugo new site bubim cd bubim git init
Paths on Windows Avoid spaces and OneDrive-synced folders for site roots. OneDrive’s file locking and virtualized placeholders confuse Hugo’s file watcher during hugo server.
Add a theme
Three ways to install a theme. Submodule is the common choice; modules are the modern one.
# A) Git submodule - tracks upstream, easy to update git submodule add https://github.com/theme/repo.git themes/mytheme # B) Hugo Modules - needs Go installed hugo mod init github.com/you/bubim hugo mod get github.com/theme/repo # C) Plain copy - simplest, you own the files (no upstream updates) git clone https://github.com/theme/repo.git themes/mytheme Remove-Item -Recurse -Force themes\mytheme\.git
Read the theme’s own README Most themes ship an exampleSite folder; copying its config and content is by far the fastest way to a working site. Theme config keys vary a lot.
Configure
baseURL = 'https://bub.im/' languageCode = 'en-us' title = 'bub.im' theme = 'mytheme' # Show future-dated and draft posts? Keep false for production. buildDrafts = false buildFuture = false # Pretty code blocks [markup.highlight] style = 'github' lineNos = false noClasses = false [params] description = 'sysadmin and security notes' author = 'cpx' [menu] [[menu.main]] name = 'Posts' url = '/posts/' weight = 10
baseURL matters It is baked into generated links. A wrong or missing trailing slash is the usual cause of broken CSS and links on the deployed site (while hugo server looked fine).
Write content
hugo new content posts/first-post.md hugo new content about.md # Page bundle: a folder with index.md + its images alongside hugo new content posts/my-guide/index.md+++ title = 'First Post' date = 2026-07-01T09:00:00+03:00 draft = true tags = ['hugo', 'windows'] +++ Body text in Markdown starts here.
Drafts are invisible draft = true pages are skipped by hugo and by hugo server unless you pass -D. Set it to false (or delete the line) to publish.
Preview locally
hugo server -D # include drafts; http://localhost:1313 hugo server -D --navigateToChanged hugo server --disableFastRender # when changes seem not to apply hugo server --bind 0.0.0.0 # reachable from another device on the LAN
Firewall prompt Windows Defender will ask to allow Hugo the first time you bind to the network. Allow it for private networks only, and skip –bind 0.0.0.0 unless you actually need LAN access.
Build
hugo # output into .\public hugo --minify # smaller HTML/CSS/JS hugo --cleanDestinationDir # remove stale files first hugo --gc --minify # tidy the resource cache too # Sanity-check what was produced Get-ChildItem .\public | Select-Object Name, Length
public is disposable It is generated output — add public/ and resources/_gen/ to .gitignore and let your host build from source instead of committing it.
Deploy
# Git-based hosts (Netlify, Cloudflare Pages, GitHub Pages) build for you git add -A git commit -m "new post" git push # Or ship the built folder to your own web server scp -r .\public\* user@server:/var/www/bubim/ # Or sync to a local/NAS path robocopy .\public \\nas\web\bubim /MIR
Pin the version Hosted builders default to whatever Hugo version they ship. Set HUGO_VERSION in the host’s build environment to match your machine, and specify extended, or a Sass theme will build locally and fail remotely.
Commands
| Command | Does |
|---|---|
| hugo | Build the site into ./public. |
| hugo server | Dev server with live reload (:1313). |
| hugo server -D | Include drafts. |
| hugo new site NAME | Scaffold a new site. |
| hugo new content PATH | Create a content file from an archetype. |
| hugo new theme NAME | Scaffold a theme skeleton. |
| hugo –minify | Minify output. |
| hugo –cleanDestinationDir | Delete stale files in public first. |
| hugo mod init / get / tidy | Hugo Modules (needs Go). |
| hugo list drafts / future / expired | Find unpublished content. |
| hugo config | Print the effective merged configuration. |
| hugo version / env | Version and build environment. |
Useful flags -D drafts, -F future-dated, -E expired, -s DIR source dir, -d DIR destination, –gc clean cache, –logLevel debug.
Project structure
| Folder | Holds |
|---|---|
| content\ | Markdown pages; folders become sections. |
| layouts\ | Your templates; override the theme’s by matching its path. |
| static\ | Copied verbatim to the site root (favicon, robots.txt). |
| assets\ | Files processed by the pipeline (Sass, JS, images). |
| data\ | TOML/YAML/JSON consumed by templates. |
| archetypes\ | Front-matter templates for hugo new. |
| themes\ | Installed themes. |
| public\ | Build output (gitignore it). |
| hugo.toml | Site configuration. |
Override, do not edit To change a theme file, copy it into your own layouts\ at the same relative path. Yours wins, and theme updates stay clean.
Front matter
| Key | Effect |
|---|---|
| title | Page title. |
| date | Publish date; drives ordering. |
| draft | true hides it unless -D. |
| tags / categories | Taxonomy terms. |
| weight | Manual ordering (lower first). |
| slug / url | Override the generated path. |
| summary | Explicit excerpt for lists. |
| layout / type | Force a specific template. |
| expiryDate / publishDate | Scheduled un/publishing. |
Delimiters TOML uses +++, YAML uses —, JSON uses braces. Pick one and stay consistent across the site.
Template basics
{{ .Title }} // page variables {{ .Content }} {{ .Site.Title }} // site-wide {{ .Params.author }} // custom front matter {{ range .Pages }} // loop <a href="{{ .RelPermalink }}">{{ .Title }}</a> {{ end }} {{ if .Params.featured }}...{{ end }} {{ with .Params.subtitle }}{{ . }}{{ end }} {{ partial "header.html" . }} // reuse {{ .Date.Format "2006-01-02" }} // Go reference date!| Template | Renders |
|---|---|
| layouts\_default\baseof.html | The shell every page inherits. |
| layouts\_default\single.html | A single page. |
| layouts\_default\list.html | Section and taxonomy lists. |
| layouts\index.html | The home page. |
| layouts\partials\*.html | Reusable fragments. |
| layouts\shortcodes\*.html | Custom shortcodes. |
The date format trap Go formats dates with the reference date 2006-01-02 15:04:05 — those exact numbers are the pattern, not an example date.
Built-in shortcodes
| Shortcode | Inserts |
|---|---|
| {{< figure src=”a.jpg” >}} | Image with caption markup. |
| {{< highlight go >}} | Syntax-highlighted code block. |
| {{< ref “post.md” >}} | Absolute link to another page (build-time checked). |
| {{< relref “post.md” >}} | Relative link to another page. |
| {{< youtube ID >}} | Embedded video. |
| {{< gist user id >}} | Embedded gist. |
| {{< param key >}} | A front-matter value inline. |
Angle brackets vs percent {{< >}} passes raw HTML through; {{% %}} renders the inner content as Markdown first.
Windows troubleshooting
| Symptom | Fix |
|---|---|
| “hugo is not recognized” | Open a new terminal so PATH reloads; confirm with where.exe hugo. |
| Sass / SCSS build errors | You are on the plain edition — install Hugo.Hugo.Extended. For modern Sass syntax add Dart Sass. |
| Theme folder is empty | Submodule not fetched: git submodule update –init –recursive. |
| Live reload not firing | Move the site off OneDrive; try –disableFastRender. |
| CSS missing after deploy | Wrong baseURL (or missing trailing slash) in hugo.toml. |
| Posts do not appear | draft = true, or a future date. Check hugo list drafts / future. |
| Port 1313 already in use | hugo server -p 1414, or stop the other instance. |
| Builds fine locally, fails on host | Host uses a different Hugo version/edition — pin HUGO_VERSION and use extended. |
Optimize
| Area | Lever |
|---|---|
| Output size | hugo –minify –gc for production builds. |
| Images | Use page bundles + Hugo’s image processing (resize/WebP) rather than shipping full-size originals. |
| Clean builds | –cleanDestinationDir so renamed pages leave no orphans behind. |
| Dev speed | Keep the site off OneDrive and out of a synced folder; local SSD paths only. |
| Reproducibility | Pin the Hugo version locally and on the host; commit the theme as a submodule at a known commit. |
| Diagnostics | hugo –templateMetrics to find slow templates; hugo config to see effective settings. |
| Link safety | Use ref / relref so broken internal links fail the build instead of shipping. |
| Repo hygiene | gitignore public/ and resources/_gen/; build from source on the host. |
References
| Resource | Use | Link |
|---|---|---|
| Hugo docs | Full reference | gohugo.io/documentation |
| Windows install | Official install page | gohugo.io/installation/windows |
| Themes | Theme gallery | themes.gohugo.io |
| gohugoio/hugo | Releases and issues | github.com/gohugoio/hugo |

0 comments