Right, let’s talk about the theme.toml file. This is your theme’s handshake, its business card, and its legally binding contract with Hugo, all rolled into one. Get this wrong, and Hugo will either throw a fit or, worse, build your theme with a whimper instead of a bang. It’s a TOML file because, well, the Hugo team made a choice. I don’t question the cosmic reasoning; I just write the config.

The file lives in the root of your theme directory (themes/your-theme-name/theme.toml), and its primary job is to tell Hugo everything it needs to know about your masterpiece before it even glances at your templates.

The Non-Negotiable Basics

You must have a name and a version. Forget these, and your theme is a philosophical exercise, not a functional piece of software. The name should match your theme’s directory name to avoid an identity crisis. The version is for you, so use semantic versioning (e.g., 0.1.0) even if you’re the only one who will ever see it. It’s good practice, and it makes you look like you know what you’re doing.

name = "my-brilliant-theme"
version = "0.1.0"

Describing Your Magnum Opus

This is where you sell your theme, mostly to yourself in the terminal output. description is a one-liner. license is MIT, because you’re not a monster and you want people to actually use your work. homepage is probably your GitHub repo URL for now.

description = "A theme that is both brilliant and minimally functional."
license = "MIT"
homepage = "https://github.com/your-username/my-brilliant-theme"

Author Information: Taking Credit

This section is pure vanity, and I am here for it. author is your name or handle. tags are crucial—they’re how the world will find your theme in the Hugo directory later. Be specific. “Blog” is useless; “personal-blog, minimal, dark-mode” is much better.

[author]
    name = "Your Name"
    homepage = "https://your-website.com"

tags = ["blog", "minimal", "responsive", "dark-mode"]

The Feature Set: Lying to Hugo (A Little)

Here’s where things get a bit… theatrical. The [config] block with features doesn’t actually enable these features in your theme. It declares which ones your theme is prepared to handle. It’s like telling Hugo, “Hey, if the user wants to use these, my templates won’t explode, I promise.”

Why? Because this list is what controls the checkboxes in the Hugo theme picker. If you don’t list "navigation" here, that option will be greyed out for a user trying to enable it via the GUI, even if your theme’s partials are perfectly capable of rendering a menu.

[config]
    [config.params]
        # These are example settings a user can configure in their config.toml
        # We'll cover these later. This section is often empty in theme.toml.

    [[config.config.settings]]
        # This isn't used often. Ignore it and move on with your life.

    [[config.config.menu]]
        # Same here. We define menus in the site config, not here.

# This is the important part:
features = ["navigation", "meta", "services", "full-width"]

Common pitfall? Listing a feature like "search" here but then forgetting to actually implement the search functionality in your layouts. You’re not enabling it; you’re just saying your theme supports it. The implementation is your job elsewhere.

The Mini-TOCs: A Questionable Default

This one is a classic head-scratcher. The min_version field is supposed to specify the minimum version of Hugo required to use your theme. In practice, most themes either omit it entirely or set it to a comically low version, because keeping it updated is a chore and breaking changes in Hugo are rare. It’s not a bad idea to set it to the version you’re actively developing on, just to cover your bases.

min_version = "0.120.0"

So, there you have it. Your theme.toml is mostly about metadata and promises. It doesn’t do much, but it tells Hugo and everyone else what your theme is. Get it right, and you’ve laid the groundwork for everything else. Now, let’s move on to the part where we actually build something.