2.5 hugo build: Generating the Public Directory
Right, so you’ve got a site full of content, some themes, maybe a few fancy shortcodes. It’s all sitting there in your content and layouts directories, which is great, but it’s not a website yet. It’s a collection of ingredients. Running hugo build is the act of turning those ingredients into a finished, served-ready meal. Or, less charitably, it’s where Hugo takes your beautifully organized thoughts and flattens them into a gigantic pile of static HTML files. It’s brilliant, it’s fast, and it’s the whole point of using a static site generator.
When you run hugo or hugo build (they are functionally identical for our purposes here), Hugo performs a symphonic feat of engineering. It reads all your content, figures out your configuration, processes any theme you’re using, and then, using the rules defined in your templates, it renders every single page of your site as a static file. It does this at a speed that would make most other generators weep with jealousy. The final product is placed neatly in the public/ directory (unless you’ve configured it otherwise). This public/ directory is your golden goose. This is what you upload to a web server. It contains nothing but HTML, CSS, JS, and images. No databases, no server-side code, just pure, fast, and secure content.
The public/ Directory is Sacred (and Ephemeral)
Here’s the first thing to burn into your brain: You do not edit anything in the public/ directory. Seriously. Don’t even open a file in there to tweak a typo. It’s a generated artifact, like a compiled binary. Any change you make will be obliterated the next time you run hugo build. Hugo owns this directory completely and will ruthlessly overwrite its contents based on the source files in your project. Your creativity and edits belong solely in the content/, layouts/, data/, and assets/ directories. This separation is what keeps you sane.
Running the Build
The simplest invocation is just:
hugo
This is equivalent to hugo build. It uses your default configuration (usually from a config.toml file in the root of your project) and builds the site to the public/ directory.
But you’ll often need more control. Here’s where the flags come in.
Taming the Output with Flags
Need to build for a different environment? Use the -e (environment) flag. This is crucial for having different settings for your development site vs. your production site (like analytics scripts).
hugo -e production
Think your content might be a bit stale? Hugo’s build is insanely fast because it tries to be smart about what’s changed. But sometimes it’s too smart for its own good. If things look weird, do a clean build to force Hugo to rebuild everything from scratch:
hugo --cleanDestinationDir
This flag tells Hugo to wipe the public/ directory clean before building, ensuring no orphaned files from a previous build are left hanging around to cause confusion.
Want to see what Hugo is actually doing during the build? The verbose flag is your friend. It’s great for debugging when you think something should be generating but isn’t.
hugo -v
The One Flag You’ll Use Every Day: -D
By default, Hugo does not build pages marked as draft: true in their front matter. This is a fantastic feature for working on posts without publishing them. But when you’re working locally, you want to see those drafts. That’s what the -D flag is for.
hugo -D
This builds the entire site, including all draft content. Your local preview is the right place to use this. For your final build that you deploy to the world, you’d omit this flag, ensuring those in-progress thoughts stay safely on your machine.
Where Does It All Go? Controlling Output
The structure within public/ mirrors your content structure and your permalink configuration. A post at content/posts/my-cool-post.md with the default permalinks will end up at public/posts/my-cool-post/index.html. Hugo builds pages as index.html files inside their own directory to create pretty, trailing-slash URLs.
If you absolutely must change the destination directory (maybe you’re integrating with another tool), use the -d or --destination flag:
hugo -d ../my-website-build
But honestly, just stick with public/. It’s standard for a reason.
The “It Built, But Where’s My New Page?” Checklist
So you ran hugo and it flew by without errors, but your brilliant new page isn’t in the public/ directory. First, don’t panic. Here’s what to check, in order:
- Is it a draft? Did you forget to use
hugo -D? Check the front matter fordraft: true. - Is the build date in the future? Hugo has a
publishDatefield. If you set a future date, Hugo will skip the page until that date arrives. It’s a feature, not a bug, I promise. - Did you look in the right place? Remember, it’s almost certainly in
public/some-path/index.html, notpublic/some-path.html. Usefind public/ -name "index.html" | grep mypageto hunt it down. - Run with verbose mode.
hugo -vwill list every page it’s rendering. If your page isn’t on that list, the issue is with the content file itself, not the build.
The hugo build command is the workhorse. It’s the moment of truth. It takes your ideas and makes them real. Respect it, learn its flags, and always remember that the public/ directory is not your friend—it’s your product.