30.3 Menu Entries: name, url, weight, identifier, parent
Right, let’s talk about the four horsemen of the menu-pocalypse: name, url, weight, identifier, and parent. These are the fields you’ll be slapping onto every menu entry in your config.toml (or yaml, or json—I don’t judge your life choices). They seem simple, but Hugo, in its infinite wisdom, gives them just enough rope to hang yourself with. I’m here to cut you down.
Think of a menu entry as a way to tell Hugo: “Hey, for this page (or even for a custom link I’m inventing out of thin air), I want you to put a thing in that navigation bar over there.” These five properties are how you tell Hugo what that thing is, where it goes, what it’s called, and crucially, where it lives in the hierarchy. Get them wrong, and your menu will look like a map drawn by a caffeine-addled squirrel.
The Core Trio: Name, URL, and Weight
First, the easy ones. The name is what actually shows up on the screen for a human to click. The url is where that click takes them. For a page, you’ll often let Hugo handle the URL based on the page’s location, but you can absolutely override it to point somewhere else, like an external site or a specific anchor.
[[menu.main]]
name = "Twitter"
url = "https://twitter.com/yourhandle"
weight = 100
The weight is your primary tool for ordering things. It’s an integer, and lower numbers (including negatives! -100 is a thing) float to the top/left, while higher numbers sink to the bottom/right. The designers of Hugo, in a moment of pure chaos, decided that the default weight for everything is 0. This means if you set one menu item to weight = 1, expecting it to be first, you’ll be horrified to find it comes after all the unweighted items that are chilling at zero. The best practice? Be explicit. Always set a weight. For your main sections, start with 10, 20, 30… it gives you room to squeeze something in between later without renumbering your entire config file.
The Secret Boss: Identifier
Now, meet the identifier. This is the field you probably ignored at first, and that’s why your menu was broken. The identifier is a unique string that Hugo uses internally to connect the dots, especially for parent-child relationships. If you don’t set one manually, Hugo will generate one for you based on the name or the page title. This is a disaster waiting to happen.
Why? Because if you change the name of your “Products” page to “Awesome Products,” the auto-generated identifier changes. Hugo suddenly has no idea that the “Pricing” page was supposed to be a child of “Products.” The parent-child relationship is severed, and “Pricing” awkwardly jumps to the top level of your menu. It’s absurd, and we’ve all been bitten by it.
The fix is stupidly simple: always manually set a stable, unique identifier. Use lowercase, use hyphens, make it something that will never change.
[[menu.main]]
identifier = "products"
name = "Products" # This can change to "Thingamajigs" later and it won't break
url = "/products/"
weight = 20
[[menu.main]]
identifier = "pricing"
name = "Pricing"
url = "/pricing/"
weight = 21
parent = "products" # This points to the identifier, NOT the name!
See that? The parent field on the “Pricing” entry points to the string "products". It doesn’t care that the parent’s name is “Products.” It only cares about its identifier. This is the most common pitfall, and manually setting identifiers is the vaccine.
Tying It All Together: The Parent Field
The parent field is what builds your nested dropdown menus. Its value must exactly match the identifier of another menu entry. That’s it. That’s the secret. There’s no magic “this page’s title” lookup. It’s a direct, literal string match.
A crucial edge case: what if you want a top-level item to also appear as a child in another menu? You can’t. A single menu entry can only exist in one place in the tree. The structure is rigid. If you need that, you have to define two separate menu entries, which is a bit annoying but gives you full control.
So, the golden rule: Control your identifiers. They are the linchpin of your entire menu structure. Be explicit with your weights to avoid ordering insanity, use name and url for what the user sees, and use parent to carefully build your hierarchy by pointing to those rock-solid identifiers. Do this, and you’ll have menus that work predictably. Ignore it, and you’ll be debugging why “Company” is suddenly the parent of “Blog” at 2 AM. I’ve been there. It’s not a good look.