Right, themes/. This directory is simultaneously the most exciting and most dangerous part of your Hugo project. It’s where you go to completely change the personality of your site without touching your precious content. Think of it like a theme park: you can have a fun, safe time on the well-maintained rides, or you can wander off into the backlot and get yelled at by a man in a stained jumpsuit for trying to hot-wire the spinning teacups.

By default, this folder is empty. You’re expected to put subdirectories here, each one a self-contained Hugo theme. The name of the subdirectory is the identifier you use to activate the theme in your config.toml.

your-project/
├── themes/
│   ├── my-awesome-theme/  # <-- This is your theme's name
│   │   ├── layouts/
│   │   ├── static/
│   │   ├── archetypes/
│   │   └── theme.toml
│   └── another-theme/
├── content/
├── static/
└── config.toml

To tell Hugo to use one, you set it in your configuration file:

# config.toml
theme = "my-awesome-theme"

The Theme Cascade: Hugo’s Hierarchy of Overrides

This is the single most important concept to grasp, and the one that saves you from forking a theme just to change a footer. Hugo has a strict order of precedence when looking for a template or file:

  1. Your project’s root directories (layouts/, static/, assets/, data/, etc.)
  2. The selected theme’s corresponding directories

Hugo looks in your project’s directories first. If it finds a file there, it uses that one and doesn’t even bother looking in the theme. If it doesn’t find it, it falls back to the theme’s version.

This is your superpower. It means you can override parts of a theme without ever touching the theme’s own code. Hate the theme’s single.html layout? Drop your own version in layouts/_default/single.html and you’ve effectively replaced it. Need to change one CSS file? Plop the updated version in static/css/style.css and yours will be used instead of the theme’s.

This approach keeps your customizations neatly in your main project, making theme updates a breeze. You can just blow away the theme directory and re-download the new version without fear of losing your changes. It’s genuinely brilliant design.

How to Actually Get a Theme In There

You have two main paths: the civilized way and the “I’m just kicking the tires” way.

The civilized way is to use Git submodules. This links the theme’s repository directly to your project, making it easy to update. This is non-negotiable for a real project.

# From the root of your Hugo project
git submodule add https://github.com/someuser/my-awesome-theme.git themes/my-awesome-theme

Later, to update all your submodules (themes) to the latest commit:

git submodule update --remote --merge

The “kicking the tires” way is to just git clone the theme directly into the themes/ directory. This is fine for a quick experiment, but it creates a nested git repository that becomes a pain to manage later. Don’t make a habit of it.

# Quick and dirty, not recommended for long-term use
cd themes
git clone https://github.com/someuser/my-awesome-theme.git

The Pitfalls: When the Magic Breaks Down

This cascade system is brilliant until it isn’t. The biggest headache comes from theme updates. If a theme updates its structure—say, it renames a partial from footer.html to site-footer.html—your project’s override file at layouts/partials/footer.html suddenly becomes a dead, unused file. Hugo will now use the theme’s new site-footer.html and ignore your old footer.html. You won’t get an error; your footer will just… change. Or vanish. It’s silent and terrifying.

Another common “gotcha” is asset management. Many modern themes use Hugo Pipes (the resources directory) to compile SCSS and JS. These processes are often tightly coupled to the theme’s own file structure. Overriding a single SCSS file might be impossible without rebuilding the entire asset pipeline, forcing you to copy the whole theme’s assets directory into your project root, which defeats the purpose of easy updates. You have to read the theme’s documentation carefully to see how they expect you to customize styles.

Best Practice: Treat Themes as a Read-Only Base

Your mindset should be this: The theme is a dependency, not a starting point for your own code. Your customizations live in the root of your project, in the layouts/, static/, and assets/ directories. The themes/ directory is for code other people wrote that you can optionally use. This strict separation is what makes Hugo’s theme system so powerful and maintainable compared to the “just edit the theme files directly” approach of other systems. It forces a clean architecture, even if it feels a bit abstract at first. Stick with it. Your future self, trying to update to get a critical security fix, will thank you.