Hugo Tutorials -- Templates, Shortcodes, Pipelines & Multilingual
In this tutorial, you'll learn about Hugo Tutorials. We cover key concepts, practical examples, and best practices.
Hugo is an open-source static site generator written in Go that builds websites at blazing speed -- known for its powerful templating system, flexible content organization, and built-in asset pipeline for modern web development.
What You'll Learn
Why It Matters
Static site generators like Hugo are essential for building fast, secure, and maintainable websites. Unlike dynamic CMS platforms, Hugo pre-builds every page as static HTML, eliminating database queries and server-side processing at request time. This translates to sub-second load times, minimal hosting costs, and immunity to common CMS attack vectors such as SQL injection. At DodaTech, our tutorial site runs on Hugo and Cloudflare Pages, serving thousands of pages with near-zero latency worldwide.
Real-World Use
Teams use Hugo for documentation sites (Docker, Kubernetes, Hugo itself), marketing landing pages, personal blogs, corporate sites, and even e-commerce catalogs. Its multilingual support makes it ideal for international audiences, while the asset pipeline handles CSS purging, JS bundling, and image processing in a single build command.
Hugo Architecture Overview
flowchart LR A[Content *.md] --> B[Hugo Build] C[Layouts Go Templates] --> B D[Static Assets] --> B E[Config hugo.toml] --> B B --> F[Static HTML/CSS/JS] F --> G[CDN Cloudflare Pages] G --> H[User Browser] style B fill:#f90,color:#fff
Prerequisites: Basic knowledge of HTML, Markdown, and command-line usage. No Go experience needed -- template syntax is straightforward.
Go Templates -- The Foundation
Hugo uses Go's html/template package with additional functions. Every template file lives in the layouts/ directory and receives a . (dot) representing the page context.
Basic Template Example
{{/* layouts/_default/single.html */}}
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
<head>
<meta charset="utf-8">
<title>{{ if .Title }}{{ .Title }} | {{ end }}{{ .Site.Title }}</title>
<meta name="description" content="{{ .Description }}">
</head>
<body>
<header>
<h1>{{ .Title }}</h1>
<p class="date">{{ .Date.Format "January 2, 2006" }}</p>
</header>
<main>
{{ .Content }}
</main>
<footer>
<p>© {{ now.Year }} {{ .Site.Params.author }}</p>
</footer>
</body>
</html>
Expected behavior: This template renders every single page (blog post, tutorial, etc.) with a consistent HTML structure. .Title comes from frontmatter, .Content is the rendered Markdown body, and .Site.Title comes from the site config.
Template Variables and Functions
| Variable | Description | Example Value |
|---|---|---|
.Title |
Page title from frontmatter | "Hugo Tutorials" |
.Description |
Meta description | "Master Hugo static site..." |
.Date |
Publish date | 2026-06-22 |
.WordCount |
Word count of content | 1450 |
.Summary |
Auto-generated summary | First 70 words |
.ReadingTime |
Estimated reading minutes | 8 |
.Site.Title |
Global site title | "DodaTech Tutorials" |
Custom Shortcodes
Shortcodes are reusable template snippets that can accept parameters. They extend Markdown with complex HTML patterns.
Card Shortcode Example
Create layouts/shortcodes/card.html:
{{/* layouts/shortcodes/card.html */}}
<div class="card">
<div class="card-icon">{{ .Get "icon" | default "document-text" }}</div>
<h3><a href="{{ .Get "link" }}">{{ .Get "title" }}</a></h3>
{{ if .Get "description" }}
<p>{{ .Get "description" }}</p>
{{ end }}
</div>
Expected output: Calling the card shortcode renders a styled card with an icon, title link, and optional description. Shortcodes can also wrap content with opening and closing tag syntax.
Asset Pipeline with Hugo Pipes
Hugo Pipes processes assets at build time -- minifying, bundling, fingerprinting, and converting files.
SCSS to CSS Pipeline
{{/* layouts/partials/head.html */}}
{{ $styles := resources.Get "scss/main.scss" }}
{{ $styles = $styles | resources.ToCSS }}
{{ $styles = $styles | resources.Minify }}
{{ $styles = $styles | resources.Fingerprint "sha256" }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}">
Expected behavior: Hugo reads assets/scss/main.scss, compiles it to CSS, minifies the output, generates a SHA-256 integrity hash, and writes the fingerprinted file. The browser can cache the file indefinitely because the filename changes when the content changes.
JavaScript Bundling
{{ $js := resources.Get "js/main.js" }}
{{ $js = $js | resources.Minify | resources.Fingerprint "sha256" }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" defer></script>
Expected behavior: The JavaScript file is minified and fingerprinted, and the defer attribute ensures it executes after HTML parsing is complete.
Multilingual Mode
Hugo supports multilingual sites with language-specific content, URLs, and navigation.
Config for Multilingual
# hugo.toml
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = false
[languages]
[languages.en]
languageCode = "en-US"
languageName = "English"
weight = 1
title = "DodaTech Tutorials"
[languages.es]
languageCode = "es-ES"
languageName = "Espanol"
weight = 2
title = "Tutoriales de DodaTech"
[languages.fr]
languageCode = "fr-FR"
languageName = "Francais"
weight = 3
title = "Tutoriels DodaTech"
Expected behavior: Hugo generates separate output directories for each language (/en/, /es/, /fr/). Content files follow the naming convention file.es.md, file.fr.md, and the template accesses .Translations to list available language versions.
Common Errors
1. Template Execution Panic
If a template calls a nil value (e.g., .Params.author when not set in frontmatter), Hugo panics with a confusing error. Always check existence first: {{ if .Params.author }}{{ .Params.author }}{{ end }}.
2. Wrong baseURL in Production
Forgetting to set baseURL = "https://yoursite.com" in production config causes broken RSS links, sitemaps, and canonical URLs. Use environment-specific config files: hugo --config config/hugo.prod.toml.
3. Missing | safeHTML for HTML Content
Rendering Markdown-rendered HTML with {{ .Content }} is safe, but rendering raw HTML strings from frontmatter requires the safeHTML function: {{ .Params.custom_html | safeHTML }}. Without it, Hugo escapes HTML tags.
4. Incorrect resources.Get Path
Hugo Pipes requires assets to live in the assets/ directory, not static/. The static/ directory is copied as-is without processing. Put SCSS, JS to be processed in assets/, and raw files (fonts, downloaded libraries) in static/.
5. Translation Files Not Loading
Multilingual sites need i18n files in i18n/ directory. Missing i18n/en.yaml causes untranslated strings to show their key name. Create translation files with key-value pairs matching your templates' {{ i18n "key" }} calls.
6. Page Build Order Dependencies
Using .PrevInSection or .NextInSection without setting proper weight in frontmatter produces unpredictable navigation order. Always assign explicit weights for consistent ordering.
Practice Questions
1. What directory must processed assets (SCSS, JS) live in for Hugo Pipes?
Assets must be in the assets/ directory. The static/ directory is copied as-is without processing.
2. How do you prevent Hugo from escaping HTML rendered from a frontmatter variable?
Use the safeHTML function: {{ .Params.my_html | safeHTML }}. This tells Hugo to render the string as raw HTML rather than escaped text.
3. What is the purpose of the | resources.Fingerprint pipe?
It generates a content-hashed filename (e.g., main.a1b2c3.css) and supplies an integrity attribute for subresource integrity. This enables long-term cache headers because the filename changes when content changes.
4. How does Hugo handle multilingual content file naming?
Content files use language suffixes: file.es.md for Spanish, file.fr.md for French, and the default language file has no suffix. Hugo maps these to the language codes defined in the config.
5. Challenge: Create a shortcode that accepts two parameters -- src and alt -- and renders an optimized <img> tag with lazy loading and WebP source.
Hint: Use resources.Get and .Resize inside the shortcode to generate responsive images on the fly.
Mini Project: Build a Documentation Theme
Create a Hugo theme for a documentation site with the following features:
- A sidebar navigation partial that recursively renders
.Pagesas a nested list - A custom shortcode that wraps content in an expandable "Details" section
- Asset pipeline for SCSS compilation and JS bundling
- Breadcrumb navigation using
.Ancestors - Search page integration with a JSON index generated by Hugo
Start by scaffolding with hugo new theme docs-theme, then add layouts/_default/baseof.html as the shell, layouts/partials/sidebar.html for navigation, and layouts/shortcodes/details.html for the expandable component. Build the SCSS entry at assets/scss/main.scss and import it in the base template.
Use hugo server -D --disableFastRender to preview changes in real time.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro