21.8 Publishing a Theme: Hugo Themes Gallery Requirements
Right, so you’ve built this beautiful, clever Hugo theme. It’s a masterpiece of semantic HTML and clever partials. You, my friend, are an artist. But art locked in a closet is just hoarding. It’s time to unleash your creation upon the world via the Hugo Themes Gallery. This isn’t just a matter of pushing to GitHub and calling it a day. Hugo has a… let’s call it a particular set of requirements. They’re not difficult, but they are non-negotiable, and missing one will leave your theme languishing in “draft” status forever.
Think of the gallery not as a simple directory, but as a build pipeline that Hugo’s robots use to automatically generate screenshots and documentation for your theme. Your job is to feed them the correct inputs.
The Non-Negotiable theme.yaml
This is the heart of the operation. This file, placed in your theme’s root directory, is your theme’s manifest. Get this wrong, and nothing else matters. It’s a YAML file, so mind your indentation—spaces, not tabs, or the whole thing will spectacularly implode.
name: "My Awesome Theme"
license: "MIT"
licenselink: "https://github.com/yourname/awesome-theme/blob/main/LICENSE"
description: "A blisteringly fast, SEO-ready theme for bloggers who hate bloat."
homepage: "https://github.com/yourname/awesome-theme"
tags:
- blog
- minimal
- responsive
features:
- syntax highlighting
- related content
- search
- dark mode
Let’s break this down because I’ve seen people mess this up:
- name: Make it unique. “Blog” is already taken. About forty times.
- license: Use a standard OSI-approved license.
MIT,Apache-2.0,GPL-3.0are all safe bets. This isn’t just a formality; it tells users what they can and can’t do with your code. - licenselink: A direct URL to the
LICENSEfile in your repo. This is a classic pitfall: forgetting to add aLICENSEfile to your repo and then linking to it. The link will 404, and your theme will be rejected. - description: Sell it! But be accurate. Don’t say “e-commerce” if it can’t handle shopping carts.
- tags & features: Be honest and precise. These are used for filtering on the gallery. If you list “search” as a feature, your theme damn well better have a search function built in. The gallery curators will check.
The Demo Content Crucible
Here’s where most first-timers get tripped up. The Hugo bots need to generate a screenshot. To do that, they need to build your theme. To build it successfully, they need content. You must provide a complete set of example content within your theme repository, in an exampleSite directory.
/my-awesome-theme/
├── archetypes/
├── layouts/
├── static/
├── theme.toml
└── exampleSite/ # <-- This is crucial
├── config.toml # <-- This points to your theme
├── content/ # <-- Full of sample posts and pages
└── static/ # (optional) Any extra demo files
The exampleSite/config.toml file is the maestro. It must point back to the parent theme directory. You do this with the theme directive. I’ve lost count of the number of themes I’ve seen that forget this and essentially point to nothing.
baseURL = "https://example.com/"
languageCode = "en-us"
title = "My Awesome Theme Demo"
theme = "my-awesome-theme" # This MUST match the folder name of your theme
# Include any other parameters your theme requires to look its best.
[params]
author = "Your Name"
description = "This is the demo site for my fantastic theme."
Populate exampleSite/content with a handful of posts that show off your theme’s features: short posts, long posts, posts with images, posts with code blocks (to show off your syntax highlighting), and a few pages. This proves your theme works in the real world and isn’t just a pretty placeholder.
The Mechanical Turk (a.k.a. The GitHub Action)
You don’t manually submit your theme. Instead, you fork the hugoThemes repository, add your theme as a git submodule to the /themes directory, and submit a pull request. It feels a bit convoluted, but it’s how they automate everything.
Once your PR is open, a Hugo bot will spring into action. It will clone your repository, build the exampleSite, and if everything passes, it will generate a screenshot and add your theme to the queue for human review. If the build fails (which it will if you missed any of the steps above), the bot will tell you, and your PR will sit there, sad and broken.
The human review is mostly about checking for quality and that the theme.yaml features aren’t lies. They’ll ensure it’s genuinely a Hugo theme and not, say, a screenshot of a cat wearing a hat (tempting, but rejected).
So, to recap: get your theme.yaml perfect, build a bulletproof exampleSite that actually builds, and then jump through the git submodule PR hoop. Do it right, and you’ll join the ranks of the published. Do it wrong, and you’ll be debugging YAML at 2 AM. I know which one I’d choose.