惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
T
Threatpost
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
Recorded Future
Recorded Future
小众软件
小众软件
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
博客园 - 聂微东
美团技术团队
F
Fortinet All Blogs
I
InfoQ
U
Unit 42
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
The Cloudflare Blog
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
GbyAI
GbyAI
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
H
Help Net Security
B
Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
aimingoo的专栏
aimingoo的专栏
C
Check Point Blog
Jina AI
Jina AI
The Register - Security
The Register - Security
Hugging Face - Blog
Hugging Face - Blog
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 叶小钗
Recent Announcements
Recent Announcements
D
DataBreaches.Net
IT之家
IT之家
雷峰网
雷峰网
Y
Y Combinator Blog
W
WeLiveSecurity
P
Proofpoint News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 司徒正美
月光博客
月光博客
The Hacker News
The Hacker News

CloudCannon Blog

Building with AI: Git-based vs headless vs traditional CMS CloudCannon + Astro: performance meets powerful content management Introducing the Astro Component Starter Introducing Jetstream — built on the Astro Component Starter Why we switched to the system font stack Redesigning CloudCannon’s docs with Diátaxis, Lume, and Pagefind Make content editing more visual: upgraded Editable Regions How Configuration Mode makes building editing interfaces easy Your hosting just got an upgrade (and a price cut) Custom testing domains for professional branding Keep your content consistent with input validation Managing multilingual content in CloudCannon Simplify team publishing with conflict resolution and domain tools Open Beta: Publishing Conflict Resolution Getting started with CloudCannon and Astro: Bookshop, components, and live editing Welcome to the CloudCannon Community! Omnichannel delivery is just marketing spin from API-based CMS companies Getting started with CloudCannon and Astro: Snippets and Collections Managing digital assets in CloudCannon: a guide to smart asset storage Understanding CloudCannon's branching workflows and Projects: a complete guide What is a static website? CloudCannon’s 2024 wrapped Getting started with CloudCannon and Astro: WYSIWYG blogging Jamstack vs. WordPress: reasons to make the change The top five static site generators for 2025 (and when to use them!) Free Jekyll themes for 2025: ten great community options Eleventy (11ty) vs. Hugo How to set up WYSIWYG editing with MkDocs Material The rise of static-first websites: why major brands are making the switch Watching your Core Web Vitals on Jamstack Understanding the difference between static, dynamic, and hybrid websites Looking for an alternative to Netlify CMS or Decap CMS? Designing components for your website editors: a CloudCannon case study Does my website look big in this? Six tips to lower your page weight Content is sacred — so own your revision history The eternal balancing act: load time vs. delay time Streamlined Headless Mode, Unified Configuration, and live data editing What is a headless CMS? Looking for a TinaCMS or Tina Cloud alternative? Coming soon: Live config editing and data reloading Faster publishing workflows out now! Why information architecture matters for your website Website UX vs SEO: picking your battles Easily manage your multilingual Astro site in CloudCannon How you can optimize publishing workflows for your content team How you can optimize your CMS for SEO success How you can optimize your Content Editor for long-form articles How you can optimize your Visual Editor for page building Secure, swift, and stable: static sites for the financial sector Enhanced flexibility for teams with Custom Permissions Building static sites that scale The Inaugural 11ty International Symposium on Making Web Sites Real Good How to manage hundreds of connected websites with a Git-based headless CMS How we’re building CloudCannon for accessibility CloudCannon’s new editing improvements are here! Open Beta | New ways to collaborate on editing your websites Top 11 free Eleventy themes for 2024 Top 10 free Astro themes to use in 2024 Why choose a Git-based headless CMS over a monolithic DXP in 2024? Learning web development: a self-guided roadmap Partner Site of the Month: Blüthner Piano Centre, by Winteractive CloudCannon’s 2023 wrapup Let’s create a microblog with visual editing using Bookshop and Eleventy Update and visualize your branches with CloudCannon Projects What is a Git-based CMS and why you should use one CloudCannon secures SOC 2 certification The complete guide to growing your web development agency Automatically optimize your images with Eleventy Image and CloudCannon Share components and syndicate content with Site Mounting Partner Site of the Month: Cru Uncorked, by Ed Meehan New web component for responsive HTML tables Wrapping up HugoConf 2023 Partner Site of the Month: Van Dillen Antieke Bouwmaterialen, by Fulldev How to become a freelance web developer: a comprehensive guide Q3 2023: CloudCannon features and improvements 22 ways to deliver more value to your web development clients Partner Site of the Month: DC Gay Flag Football League, by Ed Cupaioli A new way to configure your CloudCannon sites CloudCannon — the official CMS partner of Eleventy Full CloudCannon support for Nuxt static sites Partner Site of the Month: Stadium Bike, by Insight Creative, Inc. HugoConf 2023, brought to you by CloudCannon DAM Support for Cloudflare R2 and DigitalOcean Spaces Eleventy (11ty) vs. Gatsby in 2023 – which SSG is best for you? How CloudCannon’s live editing works with Astro and Bookshop Partner Site of the Month: Fiducian, by Croissant & Baguette Eleventy (11ty) vs. Astro How to customize CloudCannon’s Client Sharing interface Let anyone, anywhere, edit your CloudCannon sites Top 23 free Astro themes for building out-of-this-world static sites in 2023 How Jampack optimizes our Eleventy website and improves performance Astro vs. Next.js CloudCannon.com is now built with Eleventy! Out-of-this-world support for all Astro users Introducing the CloudCannon Partner Program Full CloudCannon support for Gatsby Top 10 Free SvelteKit Themes for Building Lighting-Fast Static Sites in 2023 Enhanced CloudCannon support for Next.js users Upcoming CloudCannon Interface improvements (Open Beta) Creating sites, the Jamstack way
The ultimate guide to Hugo Sections
2024-09-18 · via CloudCannon Blog

Because URLs ideally should never change, one of the critical steps in your early planning for a website project must be to decide on the site’s structure. Additionally, if you’re converting an existing website to a different platform, you must make such decisions while also respecting the site’s current URLs. Sure, redirects are possible if needed, but their use should be a last resort.

The good news is that, if you use the Hugo static site generator (SSG), you’re the boss with a capital B when it comes to how you arrange a website.

A possibly challenging aspect to such power is that, first, you need to wrap your brain around Hugo’s concept of sections. Helping you do that is the purpose of this article.

Walk before we run Direct link to this section

First, let’s cover some basics about how content management works in Hugo.

One of the numerous pillars of Hugo is how completely it takes its orders from you concerning how to structure a site’s content. As the Hugo “Content Organization” documentation says:

Hugo assumes that the same structure that works to organize your source content is used to organize the rendered site.

While this Hugo advantage is great enough if you’re just starting with a new site, it is utterly invaluable when you have to recreate an existing site — particularly one with “turtles-all-the-way-down” levels of URLs.

When you look through the code of many existing websites, even those built with SSGs, you often may have some difficulty in determining the locations of those sites’ content. That’s not a problem with a Hugo site. The default arrangement is beautifully logical: content goes in a Hugo project’s top-level content/ folder, and Hugo bases the overall site structure on what you put, and where, in that folder — which we’ll explain further as we move on to understanding Hugo sections.

(Be advised that we depict content files as .md files in this article only because Markdown tends to be the most common content format in a typical Hugo project, although Hugo supports several other formats.)

The ABCs (or XYZs) of sections Direct link to this section

Let’s say you’re working on a website for XYZ Company, with the main URL of xyzcompany.com. It needs the following top-level URLs:

  • xyzcompany.com/about-us/
  • xyzcompany.com/blog/
  • xyzcompany.com/contact/
  • xyzcompany.com/product1/
  • xyzcompany.com/product2/
  • xyzcompany.com/support/

Within most of those top levels will be separate, lower-level URLs with their own content, and further on down as appropriate. That’s a pretty common setup, right? So, in Hugo, you could start by arranging content/ like so:

.
└── content
    └── about-us
    └── blog
    └── contact
    └── product1
    └── product2
    └── support

**A content folder is automatically a section **if the folder has an index file called _index.md. (Note the underscore in that name; we’ll say more about it later on.) This causes Hugo to create a navigable URL for the section. For example, if content/about-us/_index.md exists, Hugo would create xyzcompany.com/about-us/.

Want to create a subsection, which Hugo documentation calls a nested section? That’s simple: just add a subfolder with its own _index.md file. You can do so for as many levels down as you want.

You could further enhance the structure of content/blog/ as follows:

.
└── content
    └── blog
        └── _index.md
        └── 2023
            └── fy-2023-results.md
            └── welcome-to-our-new-blog.md
            └── xyz-company-and-the-pandemic.md
        └── 2024
            └── 2024-roadmap.md
            └── awards-announcement.md
            └── fy-2024-results.md
            └── new-markets-for-xyz-company.md
            └── product0-reaches-eol.md
            └── product1-market-share.md
            └── releasing-product2.md
        └── 2025
            └── 2025-roadmap.md
            └── new-support-policies.md

See those .md files under content/blog/2023/, content/blog/2024/, and content/blog/2025? Hugo automatically creates navigable pages from any content files within a section, regardless of how many levels they may be below the section’s top level (in this case, content/blog/). Thus, the XYZ Company’s blog will include web pages at xyzcompany.com/blog/2023/fy-2023-results/, xyzcompany.com/blog/2022/awards-announcement/, and so on. This all happens because of the presence of that content/blog/_index.md file, as we’ll soon explain.

By default, Hugo considers a section’s top-level web page to be a list of the web pages within the section. Using the most recent example above, this means xyzcompany.com/blog/ would be a list of all the site’s blog posts within content/blog/ (if you added a loop to display them, that is). Later, we’ll talk about how to exercise more control over what one would find at that URL.

Now, look at this further breakdown of the overall example:

.
└── content
    └── about-us
        └── leadership

If the XYZ Company site is to have only one page for the “leadership” content, content/about-us/leadership/ needn’t be a nested section. So — because content/about-us/ is a section — either of the following will result in a regular, single page at xyzcompany.com/about-us/leadership/:

  • content/about-us/leadership/index.md
  • content/about-us/leadership.md

You can see that, in this case, the index file is called index.md rather than _index.md. But why? Read on.

Bundles — and that pesky underscore Direct link to this section

We’re now delving into a potentially puzzling aspect of Hugo site structure, namely the ever-popular “_index.md vs. index.md” question: which one do you use, and why?

That brings us to Hugo’s page bundles. They’re mainly a way to group content with any related resources, such as images and PDFs. Hugo uses a tree metaphor to define the two most commonly encountered bundle types:

  • Branch bundle — Its index file is called _index.md. It can have “children,” such as nested folders. If there are additional .md files within, each will get its own navigable URL. As we hinted earlier, only a folder that’s a branch bundle can be a section. By default, Hugo treats its index file as a list of the section’s contents, but, as we’ll see, you can exercise more control over this.
  • Leaf bundle — Its index file is called index.md and, at build time, becomes a regular web page, not a list. It can’t be a section, and therefore can have no “children.” Any additional .md file in a leaf bundle won’t get its own navigable URL Other items within a leaf bundle are page resources for the index.md file (more on that in the following example).

Perhaps the XYZ Company website has this for product1:

.
└── content
    └── product1
        └── index.md
        └── prod1_brochure_large.pdf
        └── prod1_brochure_small.pdf
        └── prod1_hero_img.jpg
        └── prod1_users_img1.jpg
        └── prod1_users_img2.jpg
        └── prod1_users_img3.jpg

Because its index file is index.md, content/product1/ is a leaf bundle. If we add another .md file to this folder, it will not have its own navigable URL. The other contents are available as “local” page resources; e.g., content/product1/index.md can link to the brochures’ PDFs as follows, without having to give the entire path in each case:

Available brochures: [large](prod1_brochure_large.pdf); [small](prod1_brochure_small.pdf).

On the other hand, suppose this is the product2 section:

.
└── content
    └── product2
        └── _index.md
        └── awards
            └── 2023.md
            └── 2024.md
            └── 2025.md
        └── brochures
            └── index.md
            └── prod2_brochure_large.pdf
            └── prod2_brochure_small.pdf
        └── extended-warranty.md
        └── images
            └── prod2_awards_img.jpg
            └── prod2_ext-warr_img.jpg
            └── prod2_hero_img.jpg
            └── prod2_users_img1.jpg
            └── prod2_users_img2.jpg
            └── prod2_users_img3.jpg

This is a branch bundle because it has _index.md in its top level, so content/product2/extended-warranty.md will become xyzcompany.com/product2/extended-warranty/. And, also because content/product2/ is a branch bundle, Hugo will convert any of its subfolders’ .md files to navigable URLs: e.g., content/product2/awards/2023.md will become xyzcompany.com/product2/awards/2023/.

Is it best for xyzcompany.com/product2/ to be merely a list of its section’s content? Probably not. So let’s cover how you can make sure it’s simply a regular web page with the content and appearance you want.

Taking the templating reins Direct link to this section

A typical Hugo site has, at the very least, the following layout templates:

.
└── layouts
    └── _default
        └── baseof.html
        └── list.html
        └── single.html
    └── index.html

(If you were using a theme called my-theme, all of the above would go under themes/my-theme/, but we’ll stick with this more minimal example since it’s easier to understand at a glance.)

By default, Hugo will assign layouts/_default/single.html as the template for a folder’s index.md, while it makes layouts/_default/list.html the template for a section’s _index.md. (layouts/index.html is for the site’s home page; if this layout isn’t present, the home page falls back to layouts/_default/single.html.) This standard behavior is unlikely to be suitable in all cases, especially as a site’s structure becomes more complex, so this is where additional considerations come into the picture.

Once more, we’ll borrow from our earlier example:

.
└── content
    └── about-us
        └── _index.md
        └── company-history.md
        └── office-locations.md
    └── support
        └── index.md

If left as-is, this would mean:

  • xyzcompany.com/about-us/ would have the look-and-feel of the layouts/_default/list.html template.
  • xyzcompany.com/about-us/company-history/, xyzcompany.com/about-us/office-locations, and xyzcompany.com/support/ each would use the look-and-feel of the layouts/_default/single.html template.

Moreover, each of these .md files’ resulting web pages would have only whatever content (if any) the applicable template allows. That’s probably not what you want. Instead, you can add new templates to get around Hugo’s default behavior. This is possible partly because Hugo assigns a content type to each content file, and the type determines the layout it will take.

The type for a top-level section’s _index.md file is automatically the section’s folder name. For example, the type for content/about-us/_index.md is about-us. (This is sufficient at the top level; we’ll discuss types and subsections in a bit.)

You can manually assign the type for a content file whose immediate folder is not a section, as would be the case for content/about-us/offices/index.md.

How can we make a section’s content files look different from the site’s default templates? The answer is: we can create templates with the same nesting in layouts/ as the content files have in content/. When you do this, it will make the content files use these templates instead of the site’s defaults:

.
└── content
    └── about-us
        └── _index.md
        └── company-history.md
        └── office-locations.md
└── layouts
    └── about-us
        └── section.html
        └── single.html

Note the presence of that about-us/section.html file? The about-us index file will use it by default, so you can make this section look and work in whatever manner works best for your site. (For safety’s sake, you may wish to refer to Hugo’s lookup order documentation.)

For the other .md pages at the level of content/about-uscontent/about-us/company-history.md and content/about-us/office-locations.md — the layouts/about-us/single.html template comes into play, ensuring that those pages won’t rely on the site-wide default single.html template.

And what about a content file whose immediate folder is not a section, like content/support/index.md? In that case, create layouts/support/single.html:

.
└── content
    └── support
        └── index.md
└── layouts
    └── support
        └── single.html

Then, in the front matter for content/support/index.md, add a key of type and a value of "support":

---
type: "support"
title: "XYZ Company Customer Support"
date: 2014-07-01T14:00:00-06:00
lastmod: 2024-02-28T15:37:00-06:00

---

As you go further down the levels, just apply the appropriate procedure based on whether a folder is a section and where the desired template is located. Let’s say content/about-us/ has a subsection about how XYZ Company contributes to various charities:

.
└── content
    └── about-us
        └── _index.md
        └── company-history.md
        └── office-locations.md
        └── philanthropy
            └── _index.md
            └── 2024-charity-drive.md
            └── previous-years.md

To give xyzcompany.com/about-us/philanthropy/ its own separate layout, you’d create layouts/about-us/philanthropy/section.html because it’s a section — and specify type: "about-us/philanthropy" in the front matter of its index file. If you neglect that last part, its formatting will “cascade” down from the layouts/about-us/ level.

And what of the other two .md files therein? If it’s acceptable for them to share one layout, creating layouts/about-us/philanthropy/single.html would be sufficient. If you prefer they not look so similar, you can create a leaf bundle subfolder for each underneath content/about-us/philanthropy/ and then make layouts at corresponding levels for each within layouts/, as explained earlier. In either case, you’ll need to make the fitting type declaration in each .md file’s front matter so as to avoid the aforementioned “cascading” effect from above.

Finally: what about the templates themselves? How do you give each page more complex content than what you could derive from a simple _index.md or index.md file? And what about those items which probably should be the same site-wide, like headers and footers? Answering those questions would take us deeper into the general subject of Hugo template files than this article has the space, or scope, to cover. Nonetheless, we can make at least these two points:

  • The content for a one-off page, like our xyzcompany.com/support/ example, probably should exist largely in that page’s template rather than only the page’s index file. While this approach does require much more use of HTML and CSS, it also provides maximum control over where and how the content appears on the page.
  • Universal site-wide content, such as navigation elements and footers, should reside in partial templates (“partials”) — which, in our previous example, would exist in layouts/partials/ and be called from there with the partial command (e.g., {{ partial "footer.html" }} if the partial template is layouts/partials/footer.html).

And, yes, in case you’re wondering: considerations like these definitely could pose problems for your non-technical clients at XYZ Company after you’ve finished developing their site. Fortunately, one of the many advantages of choosing CloudCannon as the CMS for your Hugo project is that, with CloudCannon, your clients can build and edit pages visually without having to see, much less write or edit, a single line of code!

All together now Direct link to this section

This discussion of the nearly total control that Hugo gives you over a website’s structure may have you remembering a famous line from the late Stan Lee: “With great power comes great responsibility.” As you learn what we’ve explained within, you’re already assuming that responsibility. Good going! But if you’re also ruefully recalling the old saw, “It’s lonely at the top,” fear not: when you make CloudCannon part of the project, you’re not alone at all. In fact, you have the leading SSG-savvy CMS and its team at your side. You can build that site with all the power Hugo gives you, confident that CloudCannon will make it simple for your clients to use and maintain.

By the way, it’s also wise to learn from CloudCannon’s excellent Hugo tutorial by Mike Neumegen. Regarding the subjects we covered in this article, you’ll particularly want to read the parts about content and page bundles.