Learning to Hugo Part 4: Shortcodes and Archetypes



This is the fourth part of the learning to Hugo series detailing my journey to getting this site up and running! Typical dev appraoch I just installed Hugo and got going. But I have learnt a few things along the way that have improved my development time and hopefully these things will help you. In this section I'm going to explain how to use shortcodes and archetypes to create repeatable content.

Health & safety warning

I'm no web dev! My world is data and so this stuff is outside my area of expertise. I'm learning as I go and so the info I'm sharing is my interpretation of that in a way that makes sense for me as a data-person-doing-web-dev. Some of the technical aspects might be a little misunderstood and I'd love to hear from you in the comments if you think there's a better way or if I've misunderstood a concept. Hopefully outlining my understanding of it might make it easier for someone wanting to give it a go. If you want advanced CSS understanding or web development skills though these are not the posts you're looking for!
obi wan kenobi saying these are not the posts you're looking for

obi wan says these might not be the posts you're looking for


A shortcode is a snippet that can be added to your markdown file to call a built in or custom template. It's a great way of reducing complexity in post creation. There are a number of built in shortcodes and you can also roll your own. That's great for me - it's a handy way of not having to fumble through HTML all the time. I can engage my brain for a few hours to get a snippet to work and then I'll never have to remember it again!


Hugo has a number of built in shortcodes. For example, there is a Twitter shortcode which takes the tweet ID and creates an embedded tweet. Find the tweet you're after and hit the share button, from there you can grab the tweet's URL.

picture of a tweet pointing at the share icon

The URL for this tweet is https://twitter.com/justinjbird7/status/1389503945291309056. If I just take the numeric ID and place it in the tweet shortcode;

1{{< tweet 1389503945291309056 >}}

It will embed my tweet like this;

It's a fully embedded tweet!

Behind the scenes, the tweet shortcode has constructed the embed tweet coding and simply grabs the number you've passed in and applies the code to your built page. Pretty neat!


Another useful shortcode for data folks is the gist shortcode. This shortcode requires the last two sections of the gist URL. Take this URL for example;


Turn it into the following shortcode;

1{{< gist justinjbird 65e6f915b37189ac520047cb40ed8c4d >}}

And it will be embedded like this;

The main purpose for these is to reduce clutter and perhaps to reduce your need to know more complex HTML but it can also be quite a time saver. There's a host of built in shortcodes listed on the Hugo page (see more reading section below).

Page params

You can also reference front matter using the param shortcode. Here's a few examples for this page;

1{{< param categories >}}
1{{< param author >}}

So I could build up these params to create sentences;

1{{< param author >}} wrote a post about {{< param categories >}} on {{< param date >}}
2Justin wrote a post about [hugo] on 2021-05-05 11:04:00 +0100 +0100

Custom shortcodes

On top of these built in shortcodes, it's possible to create your own. I have been using this as a way to conform sections of posts, it also makes updating sections really easy too. All of my posts end with a thanks shortcode;

 2If you made it all the way down here, thanks for reading my post and enjoy your day.
 6    <picture>
 7        <source srcset="/images-shared/stuff-jb/jedi.webp">
 8        <img src="/images-shared/stuff-jb/jedi.webp" alt="#mtfbwy" defer class="lazyautosizes lazyloaded" data-sizes="auto" data-src="/images-shared/stuff-jb/jedi.webp" >
 9    </picture>
10    <figcaption>
11        <b><p class="caption">#mtfbwy</p></b>
12    </figcaption>

There are two advantages to this. Firstly, this makes all my summaries consistent. Secondly, if I ever wanted to change this section, I only have to edit the content of my shortcode and rebuild my site!

How to create a shortcode

Create a folder in your layouts folder called shortcodes, any html file created in this folder becomes a shortcode. I'll create a new file called "example-shortcode.html" which you can see here;

image showing a new file at path ./layouts/shortcodes/example-shortcode.html

And that is it! Once the file is saved it's immediately available. So then I can reference the new shortcode like this;

1{{< example-shortcode >}}

It will create that block of code on the page like this;

Example Shortcode

Check out my new shortcode!!! It's cool!


Archetypes are content templates. It is a way of constructing preconfigured front matter and content for your new posts. This can be a useful way to reduce the amount of time to create new posts. You can prepare a template with a number of preconfigured settings and once you create a new post, Hugo will apply that template to it.

Default archetype

When you create a new site, a default archetype will exist which looks like this;

2title: "{{ replace .Name "-" " " | title }}"
3date: {{ .Date }}
4draft: true

There is no content in this archetype, just front matter settings. The title of the post, the creation date and a setting to tell Hugo it is currently a draft.

This introduces another concept of Hugo which is functions. Functions are triggered when the page is built .Name refers to the name of the file and the replace function replaces any hyphens with a space thus the title of the page by default is the name of the file with spaces instead of hyphens. {{ .Date }} is the current datetime, so when you create the page, the current date and time will be stamped to the page meta. Finally, by default the page will be created as a draft.

Create a new archetype

If you create a new post using the command line, Hugo will initially look for a file named the same as the content type for the page, if it can't find one it will revert to default.md. So for example, if you create a posts.md archetype that will be applied to all new posts you create.

Here is the command to create a new post;

1hugo new posts/new.md

A page will be created at ./content/posts/new.md and will have the layout from ./layouts/archetypes/posts.md applied. The easiest approach to this is to copy the default archetype, rename the file and work from there.

Multiple archetypes

So far we've seen how to create a single template for all your posts, but what if you want to create an template for just some of your posts? So far, we've established that Hugo will look for a file with the same name as the content type, followed by default however, you can tell Hugo which archetype to use when creating the page using a switch. My site currently has two bespoke archetypes for themed posts;

  • hugo.html (this very post is an example of that layout)
  • tsqltuesday.html (this is an example of that layout)

image showing three archetypes - default, hugo and tsqltuesday

Therefore depending on which sort of post I want to create, I will run one of three commands;

1hugo new posts/drafts/my-new-tsqltuesday-post.md --kind tsqltuesday
2hugo new posts/drafts/my-new-hugo-post.md --kind hugo
3hugo new posts/drafts/my-new-sql-post.md

This is really handy for preparing a consistent layout for a series of posts because it will cut down on setup as you create new posts.

Putting them all together

Using all of these features together allows you to construct a lot of repeatable content. For example, you can create a template with multiple shortcodes and a number of preconfigured metadata values. Once you create a new post, a lot of the content has already been preconfigured. You can even include notes.

My Hugo archetype

Because I wanted to make all of these learning to Hugo posts look conistent to some extent, I set up an archetype file which looks like this;

 2title: "{{ replace .Name "-" " " | title }}"
 3date: {{ .Date }}
 4image: "/images-shared/thumbs/hugo.webp"
 6    - hugo
 8    - getting started
 9description : Something something dark side # update this
10author: "Justin"
13{{< hugo-header >}}
15<!-- put content here -->
17{{< hugo-footer >}}

So a lot of the config is pre-configured - all I need to do is update the description and add some content. The hugo-header shortcode adds the first two sections to the page including the Obi Wan image (I start writing from the "shortcodes" header) and hugo-footer adds the last two sections after "more reading".

My tsqltuesday archetype

I've been a bit more creative with this one, making a bit more use of functions;

 2title: "{{ replace .Name "-" " " | title }}"
 3date: {{ .Date }}
 4watermark: "Blog"
 5thumbnail: "/images-shared/community/tsql-tuesday.webp"
 6draft: true
 8  - tsql2sday
10    - untagged
11description : "This is my <number> contribute to TSQL Tuesday" # update number
12author: "Justin"
13post_count: # post count in words i.e. ninth, first post was 131
14host_first_name:  # first name of host
15host_surname: # second name of host
16host_blog: # url of invite
17host_twitter: # url of host's twitter
18host_request: # complete the sentence person invites us to...
21{{< tsqltuesday-header >}}
23<!-- put content here -->
25{{< tsqltuesday-footer >}}

To give you the full picture, here is the contents of my tsqltuesday-header shortcode;

2This month’s T-SQL Tuesday is hosted by {{ $.Page.Params.host_first_name }} {{ $.Page.Params.host_surname }} (<a href="{{ $.Page.Params.host_blog }}">Blog</a> | <a href="{{ $.Page.Params.host_twitter }}">Twitter</a>). {{ $.Page.Params.host_first_name }} invites us to {{ $.Page.Params.host_request }}.
4This is my {{ $.Page.Params.post_count }} contribution to T-SQL Tuesday! 

When I first started writing TSQL Tuesday posts, I was copying the content from the previous post, deleting the old content and replacing it with the new content which was just clunky and boring. I've written out this snippet so that once the post is created all I need to do is add the relevant information to the front matter and it will be applied into the wording accordingly.

Each of the functions grabs a value from the front matter and passes that into the text block. When the page is initially constructed these values will be blank, but if I add them into the front matter of the page and rebuild the site, content will get populated. The result is a fully formed sentance that looks something like this;

This month’s T-SQL Tuesday is hosted by Mikey Bronowski (Blog | Twitter). Mikey invites us to write about the outstanding tools of the trade that make your job awesome.


So in this post I've covered a few ideas on how to create repeatable content to speed up development and be able to apply changes across multiple posts in a quick and efficient way using shortcodes and archetypes. I also showed you how to apply different layouts using switches to tell Hugo which layout to apply.


Whilst I've not explored them for this sort of process, partials offer another area to create small components for your page. I have adjusted partials to alter formatting or page construct but having found a flow using archetypes and shortcodes I've not explored the art of possible with them just yet. If you have used partials to implement some of the ideas above, I'd be interested to learn what you've done.

More reading

Any comments?

I'd love to hear from you in the comments. If you think something needs more explanation or I've not quite understood a concept, if you have a question or just want to say hi please drop me a message in the comments!


If you made it all the way down here, thanks for reading my post and enjoy your day.