Learning to Hugo Part 2: Structure and Content Organisation
- hugo
- 2021-05-02
- 10 minutes to read
- getting started
Table of Contents
A long time ago in a galaxy far, far away…
This post is over 12 months old and Hugo is evolving. Please be mindful of that when reading this post, young Padawan, as it could be outdated. I try to keep things up to date as much as possible. If you think something needs updating, please let me know in the comments.
Intro
This is the second part of the learning to Hugo series detailing my journey to getting this site up and running! I am also using Hugo to configure my business website. In typical dev style, I just installed Hugo and got going. 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 am going to walk through fundamentals of directory structure and content organisation.
Health & safety warning
I am no web dev! My world is data and so this stuff is outside my area of expertise. I am learning as I go and so the info I am 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 would love to hear from you in the comments if you think there's a better way or if I have 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!
Directory Structure
Once you have run the command “Hugo New Site” your folder structure will look similar to this;
Archetypes
Is used to store preconfigured file structures, I liken these to post templates, but Hugo uses the term templates for something else. If you want all your posts to have a specific look or feel, you can create an archetype to set that structure for all future posts created using the “hugo new” command. This is great for creating a standard structure for your posts or even for designing multiple formats for different post styles. For example, for this series of posts I have created a specific file to give me a head start with some of the repeated content. I will go through this in more detail in a future post.
Content
Is where you create all your site content. Each subfolder is considered a content section. For example, if you have a folder called content/blog your site will present [site url]/blog and all content within that folder will by default be considered of type blog. This pattern is used to apply layouts to your page type. Hugo will look for a file called blog.html in the layouts folder. If no blog.html is found it will revert to default.html. By creating a specific file for a specific file / folder you can set the formatting of that directly. You can override the type by setting a specific type in the front matter of the post. Where this might come in handy is when for a specific post you want to apply a different layout. You can override the type in the front matter and then create a new layout for that type. More on that in a future post.
Data
Appears to be used differently based on your choice of theme. I use the keepit theme for https://justinjbird.me which doesn’t make use of this folder. In other themes, YAML files have been used to structure the page layout. I have not explored this in too much detail yet.
Layouts
Holds content that is used to build your static pages. Hugo refers to these as templates. There are a number of different template types. The ones I have adjusted so far are partials & shortcodes. A full Hugo page might refer to any number of partials to create the entire page, such as a header partial, or a footer partial. Shortcodes on the other hand are used within a post to speed up your development and provide you with repeatable code or code snippets. Hugo has a few built in shortcodes and you can create your own shortcodes too. Supposing you wanted to end every post with the same thank you message, you can turn that into a shortcode and add it to your post archetype. This is really powerful as it gives you the ability to amend a shortcode in future and thus propagate that change to all posts referencing that shortcode! I will go through this in more detail in a future post.
Static
Is where all static content is stored such as images, css, javascript. This content is used during build. All content within the static folder is placed in the root of the built site directory.
Themes
Is where all themes are to be stored by default. If you open a theme folder you will notice that some of the above listed folders will also appear in there. This is because Hugo has a content lookup order which starts from the site folders and then looks inside the relevant theme folder. This is important to understand for two reasons;
- if you are trying to find why a certain widget is behaving in a certain way it may be in the site’s version of that folder or it may be in the theme folder of the same name.
- if you want to override a certain widget, it is better to copy that file to the respective folder in the site and adjust it there. That way you effectively override the version in the theme rather than directly changing the theme. This means you can keep the theme clean for future updates whilst still managing your changed versions.
Build folders
The folders above are the fundamental building blocks of your site. As you develop and build your site, more folders will be generated. It’s also possible to add your own folders for notes etc. Here is mine for this site;
Here is a brief explanation of the extra folders;
- .github is used by github to automatically build my site when I push it to the remote repository.
- #notes and #upcoming are my working folders and since they aren’t native to Hugo, Hugo just ignores them.
- Assets is built once your site is built, in here you will find a file called _custom.scss where you can add your own css.
- Resources and Public are created and used as part of the build process. These appear to be good candidates for your .gitignore file.
Organisation
You have a few options when organising your content. For a single post it is possible to create a single markdown file or a folder containing a markdown file called index.md.
When built, both posts will appear with consistent URLs;
If Hugo finds a file called index.md it considers this to be a single post and uses the name of the folder it is found in as the post name. If a file is called by any other name, that becomes the post name. Examples of this;
content/posts/getting-started-part-one/index.md > [site url]/posts/getting-started-part-one
content/posts/getting-started-part-two.md > [site url]/posts/getting-started-part-two
content/posts/getting-started-part-one/foobar.md > [site url]/posts/foobar #oops
The filename index.md is recognised as a single page. Consideration should go into how or where you wish to store supporting content such as images. For the post called part one, it is possible to store images inside that very folder or even create a subfolder for images however, for the post called part two you don’t have a folder to store them in. You might consider storing them in the root folder alongside the file or storing them in the static/images folder. In the image below I have created part three and shown a few options;
Because part 2 doesn’t have a folder you will very quickly find yourself having to start giving images associated names in order to understand which post an image is used in. This is equally a consideration when making use of the static/images folder. In the image above I have called the file 001.webp but three months down the line that isn’t going to be very obvious to anyone. So it’s advisable to also consider a suitable folder structure inside of the static/images folder.
My structure
The structure I have settled on after exploring various options is this;
- ALL of my posts get a folder, this just means everything looks consistent and appeals to my OCD. But in all seriousness…you never know when you might want to add a supporting file.
- Images specific to the post will be stored in the post’s folder. Because of this, the names don’t need to be meaningful, they will simply be called 001.webp, 002.webp etc and in terms of naming files, writing the markdown, less I have to type, the more time I have to procrastinate over the post itself.
- Images that will be used by more than one post (e.g. the Hugo logo) will be stored in the static/images folder with a meaningful name. I have subfolders to help with sorting.
Here is an example;
In the image above you can see a post I wrote about being retained as a Friend of Redgate (yay!). The post has an image specific to the post and also makes use of my friends of Redgate badge, but because I might use that badge more than once I have placed it in the shared folder.
Referencing these images
The only other thing of note when using this folder structure is how to reference the images. For an image in the same folder as the index.md file, you can simply use the filename;
![this is my hugo logo alongside the image.md file](thumb.webp)
If you stored your images in a subfolder then you would use a relative path reference;
![this is my hugo logo from subfolder](./images/thumb.webp)
If you stored your images in the static folder, then you need to provide the full path but note that when built the contents of the static folder are placed at the root of the site so the “static” folder is removed from the filepath;
![this is my hugo logo from static folder](/images/logos/hugo.webp)
Flattening URLs
One other aspect of this which has been really useful is how my site manages the construction of post URLs. In my config.toml file, there is an entry under permalinks;
[Permalinks]
posts = "/:year/:filename/"
This configuration setting is telling Hugo to adjust the URL of any file it generates from the posts folder. It acquires the date from the front matter of the post and the filename and applies that as the URL. This means I can store my posts in any folder structure I wish (so long as it is inside the posts folder) but once presented at the site they will conform to this setting.
This example will also get the month from the front matter and add that to the URL. See link to info on other values that can be used.
[Permalinks]
posts = "/:year/:month/:filename/"
I have used this behaviour to split some of my posts into different folders allowing me to control which posts get shared with another site. I will cover this off in a future post.
What else did I learn
Out of the box functionality
Out of the box, Hugo has a few addressable URLs that are pretty useful to be aware of;
- [site url]/categories will return a list of all your categories.
- [site url]/tags will return a list of all your post tags.
- [site url]/index.xml is essentially your RSS feed, you can target any section of your site by changing the URL. So for instance [site url]/posts/index.html is an RSS feed for your posts folder.
Filename behaviour
- A file called _index.md is considered the index of a section/kind, and so uses the list.html template.
- A file called index.md is considered the index of a page/post, and so uses the single.html template.
ref: https://laurakalbag.com/processing-responsive-images-with-hugo/
Further reading
- Hugo docs on Organisation
- Hugo docs on Directory Structure
- Hugo docs on Content Types
- Hugo docs on Permalink configuration values
- Read more from the series
Any comments?
I would love to hear from you in the comments. If you think something needs more explanation or I have not quite understood a concept, if you have a question or just want to say hi please drop me a message in the comments!>