6.7 Cascade: Inheriting Front Matter Down a Section Tree
Right, so you’ve got your site structured into sections. Maybe you have a posts/ directory and a projects/ directory. You’ve painstakingly set the author and layout in the front matter of every single file. It works, but it feels… repetitive. And you’re right, it is. We’re programmers. We hate repetition.
This is where Hugo’s front matter cascade comes in, a feature so powerful it feels like you’re getting away with something. The core idea is simple: you can define default values for front matter in your content directory structure itself, and those values will cascade down through that section of your content tree. It’s inheritance, but for your metadata.
How to Define a Cascade
You don’t do this in config.toml. You do it right in the _index.md file at the root of any section. Think of the _index.md file as the “class definition” for all the pages (the “objects”) within that section and its subsections.
The magic happens in the cascade field, which is a list of maps. Even if you only have one set of values to cascade, you still put it in a list. Don’t ask me why; it’s just one of those things.
# content/posts/_index.md
---
title: "All Posts"
cascade:
- author: "Your Default Author Here"
layout: "single-sidebar"
draft: false
# Any other front matter goes here
---
Now, every page in content/posts/ and content/posts/subsection/ will automatically inherit author: "Your Default Author Here" and layout: "single-sidebar". You can override any of these values directly in a page’s own front matter. The local, page-specific value always wins. This is how sane inheritance works.
The Real Power: Targeted Cascading with _target
Here’s where it gets clever. What if you only want to cascade values to a specific subset of pages? You use the _target key inside your cascade map to define a filter.
Let’s say you want to add a specific tag to all posts in a drafts/ subdirectory, but nowhere else.
# content/posts/_index.md
---
title: "All Posts"
cascade:
- author: "Your Default Author Here"
layout: "post"
- _target:
path: "/posts/drafts/**" # Note the glob pattern!
tag: "draft"
draft: true # Because of course they are.
---
The _target key uses glob patterns to match content paths. The ** is crucial—it’s a recursive wildcard meaning “any file underneath drafts/”. This is insanely useful for bulk operations. Want to add a project taxonomy to every file in your content/work/ section? One entry in the cascade. Done.
The Subtle Pitfall: It’s a List, So Order Matters
This is the part that usually bites people. The cascade is a list, and Hugo processes it in order. The last value defined for a key wins. This is mostly logical until you start combining broad defaults with specific overrides.
Imagine this config:
# content/posts/_index.md
---
cascade:
- _target:
path: "/posts/**" # Applies to ALL posts
background_color: "red"
- _target:
path: "/posts/drafts/**" # Applies only to drafts
background_color: "gray"
---
A draft post will have background_color: "gray" because that’s the last rule that matches its path and sets that key. This is what you want. But watch this:
# content/posts/_index.md
---
cascade:
- _target:
path: "/posts/drafts/**" # First rule
background_color: "gray"
- _target:
path: "/posts/**" # Second rule, matches drafts TOO!
background_color: "red"
---
Now what color is a draft? It’s red. Why? Because the second, broader rule matches the draft and comes later, so it overwrites the gray from the first rule. This is the most common “it’s not working!” moment. The fix is simple: always put your broad, general rules first, and your specific overrides later in the list.
Best Practice: Keep Your Root _index.md Lean
It’s tempting to put a massive cascade in your site’s root content/_index.md file. Resist that temptation. That’s the nuclear option. It makes your defaults harder to reason about because they’re applied so globally. Instead, be surgical. Define your cascades in the _index.md file of the specific section they’re meant for (posts/, projects/, etc.). This keeps the mental model clean: “What’s true for everything in this folder?” That’s what goes in its _index.md.
This system is Hugo’s way of acknowledging that while front matter is powerful, repeating yourself is for chumps. Use it to enforce consistency, tag entire sections automatically, and make your content structure work for you, not against you. Just remember the order of that list. Seriously, I can’t stress that enough.