Alright, let’s talk about Leaf Bundles. This is where Hugo’s content organization goes from “neatly organized” to “genuinely clever.” Forget the old way of having a single post.md file and a separate /images folder you have to mentally link together. We’re adults. We can keep our things in the same room.

A Leaf Bundle is just a directory inside your content folder that represents a single page. The magic is what you put inside it. The star of the show, the non-negotiable, is an index.md file. This is your content’s main event—it holds the front matter and the body content. But here’s the kicker: you can throw other files right in there alongside it. Images, PDFs, a custom JSON data file for this specific page… you name it. Hugo will not only manage them but will also make them incredibly easy to reference from within that index.md.

Think of it like this: instead of having to write a convoluted path like /images/projects/terrible-idea-project/logo.png, you can just use logo.png. It’s a relative path. Because the image is right there, next to the content file that needs it. It’s so simple it’s almost absurd we ever did it any other way.

The Absolute Basics: Making a Leaf Bundle

You don’t “create a Leaf Bundle” in some special way. You just create a folder and put an index.md inside it. Let’s say we’re making a project page. Here’s the structure you’d set up:

content/
└── projects/
    └── my-awesome-project/  # This is the Leaf Bundle
        ├── index.md         # The main content file
        ├── project-arch.png # A co-located image
        └── spec.pdf         # A co-located PDF

Your index.md would look like a standard Hugo content file, but now you can effortlessly use those resources:

---
title: "My Awesome Project"
date: 2023-10-27
description: "A project that is definitely not a time sink."
---

Here's a diagram of the project architecture:

![Project Architecture](project-arch.png)

You can also [download the full specification](spec.pdf).

See? No path gymnastics. It’s just… the filename. Hugo, during its rendering magic, will make sure that link points to the correct resource. It’s a small thing that removes a massive amount of mental overhead.

How Page Resources Actually Work

Now, the plot thickens. Hugo doesn’t just passively serve these files. It’s smarter than that. It processes them. Every file in the bundle becomes a Page Resource, an object you can access programmatically through the .Resources object on the page.

This is where you go from “oh, that’s handy” to “wait, that’s incredible.” Let’s say you want to create a responsive image gallery with multiple sizes. You don’t need to pre-generate all the thumbnails yourself. Hugo’s image processing can do it for you, on the fly.

First, access the image resource from your index.md template. Let’s assume you’re using a single.html layout template for this page.

<!-- In your layout file: layouts/projects/single.html -->
<h1>{{ .Title }}</h1>
{{ .Content }}

<h3>Processed Image Gallery</h3>
{{ with .Resources.GetMatch "project-arch.png" }}
  {{ $small := .Resize "400x" }}
  {{ $medium := .Resize "800x" }}
  <img srcset="{{ $small.RelPermalink }} 400w, {{ $medium.RelPermalink }} 800w"
       sizes="(max-width: 600px) 400px, 800px"
       src="{{ $medium.RelPermalink }}"
       alt="Project architecture diagram" />
{{ end }}

This code finds the image named “project-arch.png” in the bundle’s resources, creates two resized versions (400px and 800px wide), and outputs a srcset for a modern, responsive image. The beauty is that these resized images are generated on the first build and cached. You get performance for free.

The Gotchas and The Glory

Of course, it’s not all sunshine and automatically-resized roses. There are rules and quirks.

  1. The index.md is Mandatory: No index.md, no Leaf Bundle. It’s just a boring old directory full of files to Hugo.
  2. Matching Resources: The .Resources.GetMatch function uses Unix-style globbing. "image*" will get the first resource it finds that starts with “image”. Be specific in your filenames to avoid surprises.
  3. Processing Power: If you have a site with thousands of pages, each with dozens of large images, the initial build time will be… significant. Hugo is powerful, but it’s not magic. This is a trade-off for incredible developer experience and optimized output.
  4. Organization Within the Bundle: You can even create subdirectories within your Leaf Bundle! This is perfect for keeping a large number of resources organized. Hugo is flatly indifferent. You’d access it with .Resources.GetMatch "diagrams/final-arch.png". The designers got this one right.

The best practice? Use Leaf Bundles for any content that is inherently a collection of assets: projects, photo galleries, product pages, anything where the thought “I need to add an image to this page” crosses your mind. It’s the difference between managing a pile of loose files and handing you a neatly labeled box for each of your ideas.