Table of ContentsQuick SummaryLeaf BundleExamples of Leaf Bundle organizationHeadless BundleBranch BundleExamples of Branch Bundle organizationBranch Bundle vs Regular SectionsSo, which bundle should I use?Upgrading to Hugo v0.32?ExamplesFurther Reading
Hugo v0.32 introduced a new feature called Page Bundles (1, 2), as a way to organize the content files. It is useful for cases where a page or section’s content needs to be split into multiple content pages for convenience, or has associated attachments like documents or images.
A Page Bundle can be one of two types:Leaf 🍃 BundleBranch 🌿 Bundle
The leaf and branch nodes from Data Structure Trees serve as a great analogy to help relate with the Hugo bundles.LeafA node with no children.BranchA node with at least one child.Quick Summary #
Here’s a quick summary of the differences between these bundle types — Details follow in the sections after.
Table 1: Leaf Bundle vs Branch BundleLeaf BundleBranch BundleUsageCollection of content and attachments for single pagesCollection of attachments for section pages (home page, sections, taxonomy list pages, term list pages)Index file nameindex.md 1_index.md 1Allowed ResourcesPage and non-page (like images, pdf, etc) typesOnly non-page (like images, pdf, etc.) typesWhere can the Resources live?At any directory level within the leaf bundle directory.Only in the directory level of the branch bundle directory i.e. the directory containing the _index.md (ref).Layout typesinglelistNestingDoes not allow nesting of more bundles under itAllows nesting of leaf or branch bundles under itExamplecontent/posts/my-post/index.mdcontent/posts/_index.mdContent from non-index page files ..Accessed only as page resourcesAccessed only as regular pages
Hugo v0.73.0 made a much needed fix — It finally renamed taxonomy Page Kind to term, and taxonomyTerm to taxonomy. Now if you have a tags = ["abc"] front-matter, tags is the taxonomy and abc is a term.Leaf Bundle #
A Leaf Bundle is a directory at any hierarchy within the content/ directory, that contains an index.md file.Examples of Leaf Bundle organization #content/ ├── about │ └── index.md ├── posts │ ├── my-post │ │ ├── content1.md │ │ ├── content2.md │ │ ├── image1.jpg │ │ ├── image2.png │ │ └── index.md │ └── my-another-post │ └── index.md └── another-section ├── .. └── not-a-leaf-bundle ├── .. └── another-leaf-bundle └── index.md
In the above example content/ directory, there are four leaf bundles:aboutThis leaf bundle is at the root level (directly under content directory) and has only the index.md.my-postThis leaf bundle has the index.md, two other content Markdown files and two image files. The content from the two non-index .md files can be accessed only as page resources, not as regular files i.e. those non-index .md files will not have their own permalinks or HTML files in public/.my-another-postThis leaf bundle has only the index.md.another-leaf-bundleThis leaf bundle is nested under couple of directories. This bundle also has only the index.md.
The hierarchy depth at which a leaf bundle is created does not matter, as long as it is not inside another leaf bundle.Headless Bundle #
A headless bundle is a bundle that is configured to not get published anywhere:It will have no Permalink and no rendered HTML in public/.It will not be part of site.RegularPages, etc.
But you can get it by site.GetPage. Here is an example:{{ $headless := site.GetPage "page" "some-headless-bundle" }} {{ $reusablePages := $headless.Resources.Match "author*" }}
Authors
{{ range $reusablePages }}
{{ .Title }}
{{ .Content }} {{ end }}
A leaf bundle can be made headless by adding below in the Front Matter (in the index.md):headless = true
Only leaf bundles can be made headless.
Example uses of headless page bundles:Shared media galleriesReusable page content “snippets”Branch Bundle #
A Branch Bundle is a directory at any hierarchy within the content/ directory, that contains an _index.md file. This _index.md can also be directly under the content/ directory, to set the Home page content and/or front-matter variables.
By default, Hugo considers the first directory level under content/ as a section. But a branch bundle can be used to create a section at any hierarchy.Examples of Branch Bundle organization #content/ ├── _index.md ├── branch-bundle-2 │ ├── branch-content1.md │ ├── branch-content2.md │ ├── image1.jpg │ ├── image2.png │ └── _index.md └── branch-bundle-3 ├── _index.md └── a-leaf-bundle └── index.md
In the above example content/ directory, there are three branch bundles (and a leaf bundle):Home page as branch bundleThe home page content is organized as a branch bundle, using _index.md directly in the content/ directory. It consists of two other branch bundles.branch-bundle-2This branch bundle has the _index.md, two other content Markdown files and two image files. The content from the two non-index .md files can be accessed only as regular pages, not as page resources. Branch bundles cannot have page resources, so any non-index Hugo recognized content file in a branch bundle can be accessed like any regular page (just like in any section.. as.. a branch bundle is a section too).branch-bundle-3This branch bundle has the _index.md and a nested leaf bundle.
The hierarchy depth at which a branch bundle is created does not matter.Branch Bundle vs Regular Sections #Branch Bundle sectionAny directory in content/ that contains the _index.md file.Regular SectionAny first-level directory in content/, and also home page and taxonomy list page .. that is not already a Branch Bundle.
Table 2: Branch Bundle section vs Regular sectionBranch Bundle SectionRegular Section.Kind"section""section".File.Path/path/to/_index.md""Layout typelistlistCan contain non-page Resources?YesNoCan contain page Resources?NoNo
Branch Bundle is basically a Section with non-page Resources.
Here’s an example snippet that can be used in a list template to distinguish between the two:{{ if (eq .Kind "section") }} {{ if (eq .File.Path "") }}
Posts in ‘{{ .Dir | default .Section }}’
{{ else }}
{{ .Title }}
Posts in ‘{{ .Dir | default .Section }}’
{{ end }} {{ end }} So, which bundle should I use? #
In summary:
If it’s a regular page or a single page where you write your content yourself, create a leaf bundle.
Page Bundles of page Kind are always leaf bundles.. and vice versa.
Otherwise, if it’s a list page which Hugo generates for you, create a branch bundle. Such pages typically are a list of regular pages or even other list pages. Pages of home, section, taxonomy and term Kind are always branch bundles.
Figure 1: Do I need a leaf bundle, or branch bundle, or none?
Figure 1: Do I need a leaf bundle, or branch bundle, or none?Upgrading to Hugo v0.32? #
All of this boils down to these few caution points if you are upgrading Hugo from a pre-0.32 version to 0.32 or a newer version:If a directory foo has an index.md (leaf bundle), that file will be the content file for that foo Regular Page.If a directory foo has an _index.md (branch bundle), that file will be the content file for that foo Section Page, and all other2 .md files in the same or deeper hierarchy levels under foo/ will become Regular Pages under that foo section.Examples #
Of course, a post like this is not complete without examples, so here they are:
Table 3: Leaf and Branch bundle examplesExampleMarkdown sourceHTML outputThis page (leaf bundle)content/posts/hugo-leaf-and-branch-bundles/duh!Leaf and branch bundle examples from ox-hugo test sitecontent/bundles/BundlesHeadless (leaf) bundle example from the samecontent page using headless bundle + Layout fetching headless bundle pagesPage using the Headless Page BundleBranch bundles used for home, taxonomy, and term Kind pagesHugo Sandbox content/ dirHugo SandboxFurther Reading #
I suggest reading the below pages in the Hugo documentation, as they complement the Page Bundles concept:Content OrganizationPage ResourcesImage Processing
The .md extension for index.md, _index.md, and all other content files in this post is just an example. The extension can be .html or any of any valid MIME type recognized by Hugo. ↩︎ ↩︎
It’s a qualified “all other” — That does not count the content files further nested in leaf and branch bundles in that foo section. ↩︎
Your h-entries should have, at minimum, the following properties:
e-content — the main content of the post
p-name — if your post is an article with a name, use this classname.
dt-published — the datetime the post was published at, in ISO8601 format, with a timezone
u-url — the canonical URL of the post, especially important on pages listing multiple posts
It’s a common convention for the published datetime to be a link to the post itself, but they can be separate if you want.
There should also be some way to discover the author of the post — either link to your homepage (which should have your h-card on it) from anywhere within the body of the page with rel=author, or optionally embed a p-author h-card in the h-entry.
The web is an expressive medium, and as such there are many other properties which you can add to your posts. Check out the h-entry documentation for a full list.
Want to be able to use h-entry data in your code? Check out the open-source implementations.