Skip to content

Hugo Theme Development — Template Lookup, Partials, Shortcodes & Pipelines

DodaTech Updated 2026-06-22 4 min read

In this tutorial, you'll learn about Hugo Theme Development. We cover key concepts, practical examples, and best practices.

Hugo theme development uses Go templating with a hierarchical lookup order to render content, with partials for reusable components, shortcodes for rich content, and asset pipelines for CSS/JS optimization.

What You'll Learn

You'll learn Hugo's template lookup order, how to create partials and shortcodes, use the asset pipeline with Sass and JS bundling, and extend Hextra or build custom themes.

Why It Matters

Hugo is the world's fastest static site generator, building 1000+ pages in under a second. Custom themes differentiate sites and enable reusable components across projects. Web Development with Hugo scales from blogs to documentation sites with thousands of pages.

Real-World Use

DodaTech tutorials run on Hugo with a custom Hextra theme, using partials for card layouts, shortcodes for FAQs and callouts, and the asset pipeline to bundle the Tailwind CSS framework.

Template Lookup Order

Hugo resolves templates using a specific lookup order based on the page kind and output format.

flowchart TD
  A[Render Page] --> B{Page Kind?}
  B -->|Home| C[layouts/index.html]
  B -->|Section| D[layouts/_default/section.html]
  B -->|Single| E[layouts/_default/single.html]
  B -->|Taxonomy| F[layouts/_default/taxonomy.html]
  C --> G{Device match?}
  D --> G
  E --> G
  F --> G
  G --> H[Type/theme-layout.html]
  H --> I[layouts/_default/baseof.html]
  style A fill:#48f,color:#fff
<!-- layouts/_default/baseof.html — Base template -->
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
<head>
  <meta charset="utf-8">
  <title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>
  {{ partialCached "head/styles.html" . }}
</head>
<body>
  {{ partial "header.html" . }}
  <main>
    {{ block "main" . }}{{ end }}
  </main>
  {{ partial "footer.html" . }}
  {{ partialCached "head/scripts.html" . }}
</body>
</html>

Expected behavior: Every page renders inside the baseof template. Blocks define sections that child templates override. Partials are reusable across templates.

Partials

Partials are reusable template files stored in layouts/partials/. Use partial for dynamic includes and partialCached for static content to improve build speed.

<!-- layouts/partials/card.html -->
<div class="card">
  <h3>{{ .title }}</h3>
  <p>{{ .description }}</p>
  {{ if .link }}
    <a href="{{ .link }}" class="card-link">Read more</a>
  {{ end }}
</div>
<!-- Using the card partial -->
{{ partial "card.html" (dict
  "title" "Cloud Computing Basics"
  "description" "Learn IaaS, PaaS, and SaaS"
  "link" "/cloud-computing/cloud-basics/"
)}}

Expected behavior: The partial renders a card div. Each call passes different data. The partial is context-independent.

Shortcodes

Shortcodes extend Markdown with reusable inline components. They accept positional and named parameters.

<!-- layouts/shortcodes/callout.html -->
{{ $type := .Get "type" | default "info" }}
{{ $icon := .Get "icon" | default "information-circle" }}
<div class="callout callout-{{ $type }}">
  <div class="callout-icon">
    {{ partial (printf "icons/%s.html" $icon) . }}
  </div>
  <div class="callout-content">
    {{ .Inner | markdownify }}
  </div>
</div>

Usage in Markdown:

{{</* callout type="warning" icon="exclamation-triangle" */>}}
**Important:** Always back up your data before migrating.
{{</* /callout */>}}

Expected behavior: Hugo renders the shortcode into styled HTML. The inner content is processed as Markdown. This is how DodaTech tutorials show warnings and tips.

Hugo Pipes (Asset Pipelines)

Hugo Pipes process assets: SCSS to CSS, JS bundling, image processing, and fingerprinting for cache busting.

<!-- layouts/partials/head/styles.html -->
{{ $options := (dict "targetPath" "css/main.css" "outputStyle" "compressed") }}
{{ $style := resources.Get "scss/main.scss" | toCSS $options | postCSS | fingerprint }}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" integrity="{{ $style.Data.Integrity }}">
<!-- layouts/partials/head/scripts.html -->
{{ $js := resources.Get "js/app.js" | js.Build (dict "minify" true) | fingerprint }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" defer></script>

Expected behavior: SCSS compiles to CSS with PostCSS processing. JS is bundled and minified. Fingerprints enable cache busting without manual version management.

Common Errors

  1. Incorrect template naming: A template named single.html in the wrong directory is ignored. Templates must follow the exact layout lookup rules.
  2. Context confusion in partials: Partials received the calling context by default. Always use . or pass explicit parameters to avoid unexpected variable resolution.
  3. Shortcodes not registered: Custom shortcodes must be .html files in layouts/shortcodes/. A typo in the filename or shortcode name silently produces no output.
  4. Forgetting to use | safeHTML: Hugo escapes HTML by default. Render raw HTML with {{ .Content | safeHTML }} or the inner content of shortcodes will be escaped.
  5. Not clearing the cache: Hugo caches partials and resources aggressively. Use hugo --gc or rm -rf resources/_gen/ to clear stale builds.
  6. Mixing Pipes versions: Hugo Pipes uses LibSASS which is deprecated. Use dartSass in config.toml for active development.

Practice Questions

  1. What is the difference between partial and partialCached? partialCached stores the rendered result in memory and serves it for subsequent calls with the same arguments, improving build speed.
  2. How does Hugo choose which template to render for a page? Hugo checks the page type, layout, kind, and output format against a lookup order of directories.
  3. What is a baseof template? A wrapper template with block sections that child templates fill. It prevents repeating the HTML boilerplate on every page.
  4. Can shortcodes be nested? Yes, Hugo supports nested shortcodes. The inner shortcode renders before the outer one processes.
  5. Challenge: Create a Hugo shortcode that renders a tabbed code block. Users pass a language and code for each tab, and the shortcode generates tab navigation with JavaScript interactivity.

Mini Project

Build a custom Hugo theme component:

  • Create a layouts/partials/related-posts.html partial that lists 3 related pages based on matching tags
  • Create a layouts/shortcodes/tabs.html shortcode for tabbed content (code examples, comparisons)
  • Set up Hugo Pipes to compile SCSS to CSS with PostCSS and Autoprefixer
  • Configure a custom output format for JSON sitemap
  • Override the Hextra single template to add a custom sidebar section
  • Test with hugo serve and verify template lookup order resolves correctly

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro