Right, let’s talk about hugo new. This is one of those commands that seems trivial until you realize it’s the entire foundation for not driving yourself insane. It’s Hugo’s way of saying, “Don’t start from an empty file, you maniac. Start from a smart empty file.”

Think of it as your personal content factory. You give it a blueprint (an archetype), and it stamps out a new page with all the right front matter fields already filled in, or at least politely suggested. This isn’t just about convenience; it’s about consistency. It ensures your blog/ posts all have a description field and your work/case-studies/ all have a client_name field. Without it, you’re just raw-dogging YAML in a text editor, and I respect you too much to let you do that.

How It Actually Works (The Magic Trick Explained)

You run hugo new content/path/to/your-page.md. Hugo isn’t just creating a folder and a file. It’s much smarter than that. It looks at that path and tries to match it to a content type. It does this by looking for a directory inside your content/ folder that matches the first part of the path.

So, if you run:

hugo new blog/2024/my-amazing-post.md

Hugo sees blog/ and thinks, “Aha! This is a ‘blog’ type of content.” It then goes looking for a blueprint specifically for the ‘blog’ type, which is a file called archetypes/blog.md. If it finds one, it uses that as the template. If it doesn’t, it falls back to the default archetypes/default.md.

Let’s make this concrete. Say you have this archetype at archetypes/blog.md:

---
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
date: {{ .Date }}
draft: true
description: ""
categories: []
tags: []
---

Summary intro goes here.




Your brilliant content here.

When you run that hugo new command, it creates content/blog/2024/my-amazing-post.md and populates it with:

---
title: "My Amazing Post"
date: 2024-05-15T14:26:01-04:00
draft: true
description: ""
categories: []
tags: []
---

Summary intro goes here.

<!--more-->

Your brilliant content here.

See what it did with the title? It used that funky Go template function to take the filename (my-amazing-post), replace the hyphens with spaces, and title-case it. It also automatically sets the date to right now and, crucially, marks the post as a draft: true. This is Hugo’s single best opinion. It means you can start writing without accidentally publishing an unfinished post to your live site when you run hugo.

Taming the Beast: Archetypes Directory Structure

The matching of content type to archetype file is straightforward, but you have to play by Hugo’s rules. The structure of your content directory must mirror the structure of your archetypes directory.

Want a special template for content in content/work/case-studies/? Then you need an archetype at archetypes/work/case-studies.md. It’s a direct mapping.

.
├── archetypes
│   ├── default.md
│   ├── blog.md
│   └── work
│       └── case-studies.md
└── content
    ├── blog
    │   └── first-post.md
    └── work
        └── case-studies
            └── acme-corp.md

Running hugo new work/case-studies/acme-corp.md will use the specific case-studies.md archetype, not the generic default.md.

The .Site.RegularPages Gotcha (And How to Beat It)

Here’s a classic “oh, Hugo, you scamp” moment. You’re a good developer. You set draft: true in your archetype. But then you write a query in a template to list all your pages, like:

{{ range .Site.RegularPages }}
    <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}

You fire up the server with hugo server and… your new draft post isn’t there. Cue five minutes of confused frustration. Why? Because hugo server doesn’t show drafts by default. It assumes you’re previewing the real site. You have to tell it explicitly to include your unfinished work:

hugo server -D

That -D flag is for --buildDrafts. It’s a tiny thing, but forgetting it has caused more confusion than almost any other Hugo quirk. Consider this your official warning.

Leveling Up: Using Go Templates in Archetypes

This is where you go from user to wizard. Archetypes aren’t just static files; they’re executed as Go templates. This gives you incredible power to automate front matter.

Need to create a filename-based slug? No problem.

slug: {{ .File.ContentBaseName }}

Want to prompt for a value? You can’t interactively prompt, but you can use the prompt function included in Hugo’s template funcs to set a default value that’s painfully obvious needs changing.

---
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
client: {{ prompt "Enter the client name: " "ACME Corporation" }}
project_date: {{ now | time.Format "2006-01-02" }}
draft: true
---

When you run hugo new, it will set the client field to the literal string “ACME Corporation”. It’s a blunt instrument, but it’s highly effective for making sure you remember to fill in a critical field. You’ll see “ACME Corporation” staring back at you from the file, and you’ll know you have to change it.

The real power move is using the * wildcard archetype. If you create an archetype named archetypes/*.md, it will be used for every new content file that doesn’t have a more specific archetype. This is perfect for applying universal defaults, like setting a default license or author for every single piece of content on your site.

So stop creating files by hand. Let the factory do the boring work. You’ve got more interesting things to write.