Hugo Core Concepts: Content Organization and Management

hugo
content-organization
taxonomies
page-bundles
best-practices
Deep dive into page bundles, taxonomies, content sections, and Hugo’s content organization patterns for scalable documentation sites
Author

Dario Airoldi

Published

January 14, 2026

Modified

March 8, 2026

Hugo Core Concepts: Content Organization and Management

📖 Overview

Hugo’s content model is fundamentally different from traditional CMSs or even other static site generators. Understanding page bundles, taxonomies, sections, and content types is crucial for building scalable, maintainable sites like the Learning Hub.

Core Concepts Covered:

  • Page bundles (leaf vs branch)
  • Taxonomies (tags, categories, custom)
  • Content sections and organization
  • Front matter architecture
  • Content relationships

📦 Page Bundles

Hugo organizes content using page bundles - directories containing a markdown file plus related resources (images, data files, etc.).

Leaf Bundles (index.md)

Leaf bundles are single pages with associated resources:

content/
└── posts/
    └── my-article/              # Leaf bundle
        ├── index.md             # Content file
        ├── image1.jpg           # Page resource
        ├── image2.png           # Page resource
        └── data.json            # Page resource

index.md:

---
title: "My Article"
date: 2026-01-14
resources:
  - src: "image1.jpg"
    name: "hero"
    title: "Hero Image"
  - src: "**.jpg"
    params:
      credits: "Photo by Author"
---

![Hero](hero)  <!-- Hugo finds image1.jpg automatically -->

Content goes here...

Accessing resources in templates:

{{ with .Resources.GetMatch "hero" }}
  <img src="{{ .Permalink }}" alt="{{ .Title }}">
{{ end }}

<!-- All images -->
{{ range .Resources.ByType "image" }}
  <img src="{{ .Permalink }}" alt="{{ .Title }}">
{{ end }}

Branch Bundles (_index.md)

Branch bundles are section pages that can have child pages:

content/
└── docs/                        # Branch bundle
    ├── _index.md                # Section homepage
    ├── getting-started.md       # Child page
    ├── configuration.md         # Child page
    └── advanced/                # Nested branch bundle
        ├── _index.md
        └── performance.md

**_index.md:**

---
title: "Documentation"
description: "Complete Hugo documentation"
weight: 10                       # Controls section ordering
---

Welcome to the documentation section.

Practical Example: Learning Hub Structure

Mapping your current Quarto structure to Hugo bundles:

Current (Quarto):

03.00-tech/
├── 02.01-azure/
│   ├── article1.md
│   ├── article2.md
│   └── images/
│       └── diagram.png
└── 05.01-github/
    └── article3.md

Hugo Equivalent:

content/
└── tech/
    ├── _index.md                    # Branch: Tech section
    ├── azure/
    │   ├── _index.md                # Branch: Azure section
    │   ├── article1/
    │   │   ├── index.md             # Leaf: Article 1
    │   │   └── diagram.png          # Resource
    │   └── article2.md              # Standalone page
    └── github/
        ├── _index.md
        └── article3.md

Benefits:

  • ✅ Resources co-located with content
  • ✅ Portable bundles (move folder = move article + images)
  • ✅ No broken relative links
  • ✅ Automatic image processing per bundle

🏷️ Taxonomies

Taxonomies are Hugo’s way of organizing and classifying content.
Built-in taxonomies include tags and categories, but you can create custom ones.

Built-in Taxonomies

Front matter:

---
title: "Introduction to Hugo"
tags: ["hugo", "static-site-generator", "tutorial"]
categories: ["Documentation", "Getting Started"]
---

Hugo automatically generates:

  • /tags/ - List of all tags
  • /tags/hugo/ - All posts tagged “hugo”
  • /categories/ - List of all categories
  • /categories/documentation/ - All posts in “Documentation”

Custom Taxonomies

For Learning Hub, we could add custom taxonomies like series and difficulty:

config.toml:

[taxonomies]
  tag = "tags"
  category = "categories"
  series = "series"              # Custom taxonomy
  difficulty = "difficulty"      # Custom taxonomy
  technology = "technologies"    # Custom taxonomy

Front matter:

---
title: "Hugo Performance Optimization"
tags: ["hugo", "performance"]
categories: ["Advanced"]
series: ["Hugo Deep Dive"]
difficulty: ["intermediate"]
technologies: ["Go", "Goldmark", "SCSS"]
---

Accessing in templates:

<!-- List all series -->
{{ range .Site.Taxonomies.series }}
  <h3>{{ .Page.Title }} ({{ .Count }} articles)</h3>
  <ul>
    {{ range .Pages }}
      <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
    {{ end }}
  </ul>
{{ end }}

<!-- Articles in same series -->
{{ with .Params.series }}
  {{ $currentSeries := index . 0 }}
  {{ $relatedPages := where site.RegularPages ".Params.series" "intersect" (slice $currentSeries) }}
  <aside>
    <h4>This Series:</h4>
    <ul>
      {{ range $relatedPages }}
        <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
      {{ end }}
    </ul>
  </aside>
{{ end }}

Practical Example: Learning Hub Taxonomies

Recommended taxonomies for this workspace:

[taxonomies]
  tag = "tags"                   # Technical topics
  category = "categories"        # Content type (tech, howto, event)
  series = "series"              # Article series
  technology = "technologies"    # Technologies covered
  event = "events"               # Conference/event name
  date_prefix = "date_prefixes"  # YYYYMMDD grouping

Example article front matter:

---
title: "Azure Functions Best Practices"
date: 2026-01-14
tags: ["azure-functions", "serverless", "best-practices"]
categories: ["tech"]
series: ["Azure Serverless Guide"]
technologies: ["Azure", "C#", ".NET"]
event: []
---

📂 Content Sections

Sections are defined by directory structure under content/. Each first-level directory becomes a section.

Section Structure

content/
├── _index.md              # Homepage (not a section)
├── posts/                 # "posts" section
│   ├── _index.md
│   └── article1.md
├── docs/                  # "docs" section
│   ├── _index.md
│   └── guide.md
└── events/                # "events" section
    ├── _index.md
    ├── build-2025/
    │   └── index.md
    └── ignite-2025/
        └── index.md

Section Templates

Hugo uses different templates based on content type:

layouts/
├── _default/              # Default templates
│   ├── list.html         # Section pages (_index.md)
│   └── single.html       # Regular pages
├── posts/                 # Custom templates for "posts" section
│   ├── list.html
│   └── single.html
└── events/                # Custom templates for "events" section
    └── single.html

Section Configuration

**content/posts/_index.md:**

---
title: "Blog Posts"
description: "Latest articles and tutorials"
cascade:                           # Apply to all descendants
  layout: "post"
  author: "Dario Airoldi"
  params:
    show_toc: true
    show_author: true
---

What is cascade?

  • Applies front matter to all pages in section
  • Inherited by child pages
  • Can be overridden per page

🎯 Content Types

Content types determine which template Hugo uses for rendering.

Automatic Type Assignment

By default, content type = section name:

content/posts/article.md     → type: "posts"
content/docs/guide.md        → type: "docs"
content/events/build.md      → type: "events"

Explicit Type Override

Front matter:

---
title: "Special Article"
type: "featured"              # Override automatic type
layout: "showcase"            # Override template
---

Template lookup:

layouts/
└── featured/
    └── showcase.html         # Used for this page

Learning Hub Content Types

Proposed structure:

content/
├── news/                      # Type: "news"
│   └── vscode-updates/
├── events/                    # Type: "events"
│   └── build-2025/
├── tech/                      # Type: "tech"
│   ├── azure/
│   └── github/
├── howto/                     # Type: "howto"
│   └── guides/
├── issues/                    # Type: "issues"
│   └── troubleshooting/
└── ideas/                     # Type: "ideas"
    ├── iqpilot/
    └── learnhub/

Custom layouts per type:

layouts/
├── news/
│   └── single.html           # News article layout
├── events/
│   └── single.html           # Event notes layout
├── tech/
│   └── single.html           # Technical article layout
└── howto/
    └── single.html           # Tutorial layout with steps

🔗 Content Relationships

Series Navigation

Automatic series ordering:

{{ with .Params.series }}
  {{ $currentSeries := index . 0 }}
  {{ $seriesPages := where site.RegularPages ".Params.series" "intersect" (slice $currentSeries) }}
  {{ $seriesPages := $seriesPages.ByParam "position" }}
  
  {{ $currentIndex := 0 }}
  {{ range $index, $page := $seriesPages }}
    {{ if eq $page.Permalink $.Permalink }}
      {{ $currentIndex = $index }}
    {{ end }}
  {{ end }}
  
  <nav class="series-nav">
    {{ if gt $currentIndex 0 }}
      {{ $prev := index $seriesPages (sub $currentIndex 1) }}
      <a href="{{ $prev.Permalink }}">{{ $prev.Title }}</a>
    {{ end }}
    
    {{ if lt $currentIndex (sub (len $seriesPages) 1) }}
      {{ $next := index $seriesPages (add $currentIndex 1) }}
      <a href="{{ $next.Permalink }}">{{ $next.Title }}</a>
    {{ end }}
  </nav>
{{ end }}

Front matter for series:

---
title: "Hugo Performance - Part 2"
series: ["Hugo Deep Dive"]
position: 2                    # Order in series
---

📋 Front Matter Architecture

Standard Fields

---
# Required
title: "Article Title"
date: 2026-01-14

# Recommended
description: "SEO description (150-160 chars)"
draft: false                   # Hide from production builds
publishDate: 2026-01-15        # Publish in future
expiryDate: 2027-01-01         # Remove after date
lastmod: 2026-01-14            # Last modified (for sitemap)

# SEO
slug: "custom-url-slug"        # Override URL
aliases:                       # Redirects from old URLs
  - /old-path/article
  - /legacy/post
keywords: ["hugo", "tutorial"]
images: ["featured.jpg"]       # Social media images

# Content
summary: "Brief excerpt..."    # Manual summary
weight: 10                     # Ordering (lower = higher)
toc: true                      # Table of contents
math: true                     # Enable KaTeX
mermaid: true                  # Enable Mermaid diagrams

# Taxonomies
tags: ["hugo", "tutorial"]
categories: ["Documentation"]
series: ["Hugo Guide"]

# Custom params
params:
  author: "Dario Airoldi"
  reading_time: 15
  difficulty: "intermediate"
  featured: true
  github_repo: "owner/repo"
---

Cascade for Defaults

**content/tech/_index.md:**

---
title: "Technical Articles"
cascade:
  params:
    author: "Dario Airoldi"
    show_toc: true
    layout: "tech-article"
    featured_in_search: true
---

All files in tech/ inherit these params (unless overridden).

🔍 Querying Content

Finding Pages

<!-- All regular pages -->
{{ range site.RegularPages }}
  {{ .Title }}
{{ end }}

<!-- Pages in specific section -->
{{ range where site.RegularPages "Section" "tech" }}
  {{ .Title }}
{{ end }}

<!-- Filter by parameter -->
{{ range where site.RegularPages ".Params.featured" true }}
  {{ .Title }}
{{ end }}

<!-- Filter by taxonomy -->
{{ range where site.RegularPages ".Params.tags" "intersect" (slice "hugo") }}
  {{ .Title }}
{{ end }}

<!-- Combine filters -->
{{ $pages := where site.RegularPages "Section" "tech" }}
{{ $pages = where $pages ".Params.difficulty" "intermediate" }}
{{ $pages = $pages.ByDate.Reverse }}
{{ range first 10 $pages }}
  {{ .Title }}
{{ end }}

Sorting and Grouping

<!-- By date (newest first) -->
{{ range site.RegularPages.ByDate.Reverse }}
  {{ .Title }}
{{ end }}

<!-- By weight (lowest first) -->
{{ range site.RegularPages.ByWeight }}
  {{ .Title }}
{{ end }}

<!-- By title alphabetically -->
{{ range site.RegularPages.ByTitle }}
  {{ .Title }}
{{ end }}

<!-- Group by year -->
{{ range site.RegularPages.GroupByDate "2006" }}
  <h2>{{ .Key }}</h2>
  {{ range .Pages }}
    <li>{{ .Title }}</li>
  {{ end }}
{{ end }}

<!-- Group by parameter -->
{{ range site.RegularPages.GroupByParam "category" }}
  <h2>{{ .Key }}</h2>
  {{ range .Pages }}
    <li>{{ .Title }}</li>
  {{ end }}
{{ end }}

💡 Best Practices for Learning Hub

Content Organization Strategy

1. Use page bundles for articles with images:

content/tech/azure/
├── functions-best-practices/
│   ├── index.md
│   ├── architecture.png
│   └── code-example.cs
└── storage-optimization.md    # No images = standalone file

2. Define custom taxonomies:

[taxonomies]
  tag = "tags"
  category = "categories"
  series = "series"
  technology = "technologies"
  event = "events"

3. Use cascade for section defaults:

---
title: "Tech Articles"
cascade:
  params:
    content_type: "technical"
    show_toc: true
    reading_time_enabled: true
---

4. Implement series navigation:

---
title: "Hugo Guide - Part 2"
series: ["Hugo Complete Guide"]
position: 2
---

5. Structure URLs logically:

[permalinks]
  posts = "/:year/:month/:slug/"
  tech = "/tech/:section/:slug/"
  events = "/events/:slug/"

🎯 Key Takeaways

  1. Page bundles co-locate content and resources - Easier maintenance
  2. Taxonomies provide flexible organization - Beyond folders
  3. Sections = first-level directories - Automatic structure
  4. Cascade inherits front matter - DRY principle
  5. Content relationships are automatic - Related content, series navigation

🔜 Next Steps

Continue to Goldmark Markdown Processing to learn about:

  • Goldmark parser configuration
  • Markdown extensions and features
  • Syntax highlighting with Chroma
  • Custom render hooks
  • Shortcodes for reusable content

📚 References