Creating Hugo Themes: A Comprehensive Guide

Based on tutorials and live workshops from Hugo experts


Table of Contents

  1. Introduction
  2. Getting Started with Hugo
  3. Understanding Hugo’s Directory Structure
  4. Creating a Hugo Theme from Scratch
  5. Layouts and Templates
  6. Partials and Shortcodes
  7. Using Hugo’s Templating Language
  8. Styling Your Theme
  9. Content Management and Archetypes
  10. Advanced Customizations
  11. Deployment and Workflow Tips
  12. Conclusion

Introduction

Creating your own Hugo theme can be a game changer if you’re not satisfied with the available options or if you want to customize every aspect of your site. This guide brings together insights from multiple video tutorials and workshops—from the basics of templating to advanced customization techniques—to help you build a Hugo theme from scratch.

Whether you’re aiming to build a personal blog, a company website, or a portfolio, this guide will provide a step-by-step approach to understand Hugo’s inner workings and to create a theme that reflects your unique style and functionality.


Getting Started with Hugo

Installing Hugo

Before you begin, ensure you have Hugo installed on your system. Hugo is available on multiple platforms—macOS, Linux, and Windows. Refer to the official Hugo installation guide for detailed instructions.

Creating a New Hugo Site

Once Hugo is installed, create a new site using the command:

hugo new site my-hugo-site

This command creates a new directory (my-hugo-site) with a default structure. In recent versions of Hugo, you may notice a file named hugo.toml created as the default configuration file.

Understanding Hugo’s Directory Structure

Hugo organizes your site into several key directories and files. Here’s a brief overview:

  • content/
    Where your Markdown content files (blog posts, pages, etc.) reside.

  • layouts/
    Contains the HTML templates that define how your content is rendered. Key subdirectories include _default/ (for default templates), and partials/ (for reusable components like headers and footers).

  • static/
    Houses static assets such as images, CSS, and JavaScript files. Files here are copied directly into the final output without processing.

  • assets/
    Optional folder used for processing assets (e.g., compiling SCSS) via Hugo Pipes.

  • archetypes/
    Contains templates that are used when you create new content using hugo new.

  • themes/
    When using themes, this directory holds theme-specific files (layouts, static, etc.). You can also create your own theme here.

  • Configuration Files:
    hugo.toml (or config.toml, config.yaml, etc.) contains site-wide settings.

Creating a Hugo Theme from Scratch

Starter Themes vs. Building Your Own

Many tutorials suggest starting with a bare-bones or starter theme. A starter theme provides the minimal structure (layouts, partials, basic CSS) that you can build upon. Alternatively, you can create your theme entirely from scratch by adding the necessary directories and files directly into your Hugo site.

Setting Up the Theme Directory

If you choose to build a theme as a separate repository (or subdirectory), the key elements are:

  • Layouts:
    Create your HTML templates in layouts/ (e.g., \_default/single.html, \_default/list.html, baseof.html).

  • Partials: Store reusable components (header, footer, nav, etc.) in layouts/partials/.

  • Static Assets:
    Place your CSS, JavaScript, and image files in static/ or within your theme’s static/ folder.

  • Theme Metadata:
    A theme.toml file in your theme directory provides metadata (name, description, version).

Hugo will prioritize layouts in your main site over those in the theme if there are conflicts, allowing you to override theme defaults.

Layouts and Templates

The Role of baseof.html

The baseof.html file is the master layout that defines the common structure (doctype, HTML, head, body) for your pages. Other templates extend this base using Hugo’s block mechanism. For example, in baseof.html you might define a block named main:

<!DOCTYPE html>
<html lang="en">
<head>
  {{ partial "head.html" . }}
</head>
<body>
  {{ partial "header.html" . }}
  <main>
    {{ block "main" . }}{{ end }}
  </main>
  {{ partial "footer.html" . }}
</body>
</html>

Single and List Templates

  • single.html:
    Used to render individual pages (blog posts, static pages).

  • list.html:
    Used for section pages that list multiple content items (e.g., blog listings, category pages).

Both templates typically extend baseof.html and define their own content blocks.

Partials and Shortcodes

Using Partials for Reusability

Partials are snippets of HTML code stored in layouts/partials/ that you can include in multiple templates. For example:

{{ partial "header.html" . }}
{{ partial "footer.html" . }}

This avoids duplication and makes it easier to maintain common sections like navigation menus and footers.

Shortcodes for Custom Content

Shortcodes allow you to create reusable content snippets that can be inserted directly into Markdown files. For instance, you might create a shortcode to display images with captions or embed videos. Their syntax in content files looks like:

A beautiful view
A beautiful view

Shortcodes are stored in the layouts/shortcodes/ directory.

Using Hugo’s Templating Language

Hugo uses Go’s templating language to provide dynamic content and logic within your HTML files.

Go Templates Basics

Template syntax in Hugo is enclosed in double curly braces {{ }}. For example:

Variables:

{{ $title := .Site.Title }}

Conditionals:

{{ if .IsHome }}
  <h1>{{ .Site.Title }}</h1>
{{ else }}
  <h1>{{ .Title }} | {{ .Site.Title }}</h1>
{{ end }}

Loops (Ranges):

{{ range .Site.Menus.main }}
  <li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}

Variables, Ranges, and Functions

Hugo templates give you access to page variables (like .Title, .Content), site variables (like .Site.Title), and many built-in functions (e.g., dateFormat, print). These enable you to manipulate data and conditionally render content.

Styling Your Theme

Static Files and the Asset Pipeline

All static assets—such as CSS, JavaScript, and images—should be placed in the static/ directory. These files are copied directly to the public output. Hugo’s asset pipeline (Hugo Pipes) can also process files placed in the assets/ directory.

Integrating Tailwind CSS

Many modern Hugo themes integrate Tailwind CSS for rapid UI development. To set this up:

  1. Initialize NPM in Your Theme Directory:
    Navigate to your theme folder and run:
npm init -y
  1. Install Tailwind CSS and Dependencies:
npm install tailwindcss postcss autoprefixer
  1. Configure Tailwind:
    Generate configuration files:
npx tailwindcss init -p

Then, create your main CSS file (e.g., assets/css/main.css) with Tailwind’s directives:

@tailwind base;
@tailwind components;
@tailwind utilities;
  1. Link the CSS in Your Theme:
    Use Hugo’s templating to link the generated CSS file in your &lt;head&gt; partial:
<link rel="stylesheet" href="{{ "css/main.css" | relURL }}">
  1. Watch and Build:
    Use NPM scripts to build and watch your CSS changes as you develop your theme.

Content Management and Archetypes

Content in Hugo is stored as Markdown files in the content/ directory. Each file contains front matter (in YAML, TOML, or JSON) that defines metadata like title, date, draft status, and custom parameters.

Archetypes in the archetypes/ directory serve as templates for new content. For example, archetypes/default.md is used to prepopulate front matter when you run:

hugo new post/my-first-post.md

Advanced Customizations

Custom Page Types and Menus

Hugo allows you to create custom page types by organizing content into subdirectories (e.g., content/about, content/blog) and by defining custom layouts for these sections (e.g., layouts/about/single.html). You can also define custom menus in your configuration file to control navigation.

Pagination, RSS, and SEO

  • Pagination:
    Use Hugo’s built-in pagination functions in your list templates to display a limited number of posts per page.

  • RSS Feeds:
    Hugo automatically generates RSS feeds if you include a template like layouts/rss.xml.

  • SEO:
    Customize meta tags and structured data within your &lt;head&gt; partial to improve SEO.

Deployment and Workflow Tips

  • Development Server:
    Run hugo server during development to see real-time changes.

  • Production Builds:
    Use hugo to generate the site in the public/ directory and deploy it to your hosting platform (e.g., S3, Netlify).

  • Configuration Management:
    Maintain separate configuration files for development and production using environment-specific configs or Hugo’s --environment flag.

  • Version Control:
    Use Git (and submodules if necessary) to manage your site, theme, and content repositories independently.

Conclusion

Creating a custom Hugo theme may seem daunting at first, but by understanding Hugo’s directory structure, templating system, and asset management, you can build a theme that perfectly suits your needs. This guide has covered the basics—from setting up a site and creating layouts to using partials, shortcodes, and integrating modern CSS frameworks like Tailwind.