Introduction#
In this post I’m going to detail the steps I followed to create this blog site using Hugo combined with the very flexible Blowfish theme. By the end of this guide, you will have a fully functional blog site that is easy to maintain and customize.
I spent a bit of time looking at different static site generators, but Hugo stood out due to its speed, ease of use, and extensive documentation. The Blowfish theme caught my eye because of its design and flexibility and like Hugo, it has great documentation!
Before we go further here are the links to both Hugo and the Blowfish theme. You can find the full documenatation for both sites at those links.
Prerequisites#
You will need to download and install some tools before you get started. This guide is not intended to be the definitive set of instructions for this step. It will depend on your operating system, how you want to install the theme and how you will be hosting the site. I’m on Windows and I’m using GitHub to host the repository and GitHub Pages to host the site. Both the Hugo and Blowfish docs are excellent and will guide you through the installation steps for your specific environment.
The Hugo docs say to use Powershell rather than Windows Powershell. I tend to use Powershell all the time so can’t say if you will run into problems using Windows PowerShell or not. Probably best to follow the docs on this one.
Create a GitHub Account#
If you don’t already have a GitHub account you will need to create one. You can do this by going to GitHub and signing up for a free account.
Install Hugo#
The easiest way to install Hugo on Windows is to use Winget.
winget install Hugo.Hugo.ExtendedYou can check that Hugo is installed correctly by running:
hugo versionInstall Git#
While Git isn’t strictly required to create a Hugo site it is very useful for managing your site files and installing themes like Blowfish. It can also be installed using Winget.
winget install --id Git.Git -e --source wingetYou will need to set-up Git with your GitHub account. The following links shows how to do this:
Setting your Git username
Setting your commit email address
Not necessary but recommended#
You may want to install a code editor like Visual Studio Code to make editing your site files easier.
You can also use a custom domain name if you have one. I’ll cover that at the end.
Creating a new Hugo site#
Now that all the prerequisites are installed we are ready to createa new Hugo site.
Open a terminal window and navigate to the folder where you want to create your site. The Hugo CLI will create an empty folder to hold the site files. Run the following command to create a new Hugo site, replace mynewsite with the name you want to use for your site:
hugo new site mynewsiteNavigate into the new site folder:
cd mynewsiteYou should now see a basic folder structure for your Hugo site. It will look something like this:
mynewsite
├── archetypes
| └── default.md
├── themes
├── content
├── data
├── i18n
├── layouts
├── static
└── hugo.tomlInitialize a new Git repository:
git initMake sure your branch is set to main:
git branch -M mainCreate a .gitignore file in the root of your project folder and add the following lines to it:
/public/
/resources/These two folders are generated by Hugo when you build your site and don’t need to be tracked in Git or pushed to your remote repository.
Installing the Blowfish theme#
You can install Blowfish by cloning the repository into the themes folder of your Hugo site. Run the following command:
git submodule add -b main https://github.com/nunocoracao/blowfish.git themes/blowfishThis is one way to install Blowfish. There are others including a CLI tool, which will initialize a new Hugo site with the Blowfish theme already installed. See the Blowfish documentation for more details.
Connecting your project to GitHub#
If you are using GitHub Pages to host your site you will need to create a new repository on GitHub. Name the repository something like mynewsite.github.io. Choose not to create a README.md in the new repository. You can now add the remote repository to your local Git repository:
git remote add origin https://github.com/<your-username>/mynewsite.github.ioCommit your changes:
git add -A
git commit -m "Initial commit"Finally, push your changes to GitHub:
git push -u origin mainConfiguring the Blowfish theme#
From here in you will find it easier to work in your code editor. I’m using Visual Studio Code. Open the project folder in your editor.
Configure Hugo to use the Blowfish theme#
In the root of your project folder you will find a file named hugo.toml. Delete this file.
Navigate to the themes/blowfish/ folder and copy the folder called config. Paste this folder into the root of your project folder.
Inside the config folder you will find a folder named _default which contains all the toml configuration files for the theme:
config
└── _default
├── hugo.toml
├── languages.en.toml
├── markup.toml
├── menus.en.toml
├── module.toml
└── params.tomlThese files contain all the Blowfish configuration options which you can use to customise your site.
I’m not going to go through an exhaustive explanation of every option as there a lot of them. I’m just highlighting the steps I took to get this site how I wanted it. You can find the full documentation here.
Configure hugo.toml#
Open hugo.toml and update the following settings to match your site:
theme = "blowfish" # UNCOMMENT THIS LINE
baseURL = "https://mynewsite.github.io/" # UNCOMMENT AND UPDATE THIS LINE (USE YOUR OWN URL)
defaultContentLanguage = "en" # Set this to the language you want to useConfigure languages.en.toml#
Open languages.en.toml. If your site is in English the file is usable as is. If your language is different you will need rename the file to match your language code and update the settings inside the file. refer to the documentation for more details on this.
Set the title options to match your site title then uncomment the [params.author] section and update with the details you want to use.
[params.author]
name = "Paul McCormack"
# email = "youremail@example.com"
image = "img/blowfish_logo.png"
imageQuality = 96
headline = "This is my site about making a site with Hugo and Blowfish!"
# bio = "A little bit about you"Use your social profile picture!
You can use your socials profile picture to save storing an image in your site. Just set the image option to the URL of your profile picture.
If you want to include links to your social profiles uncomment the relevant lines in the links section and update the urls:
links = [
# { email = "mailto:hello@your_domain.com" },
# { link = "https://link-to-some-website.com/" },
{ github = "https://github.com/paul-mccormack/" },
{ linkedin = "https://www.linkedin.com/in/paul-mccormack-08b04a6/" },
] # Scroll down to the bottom of the file and uncomment this line alsoConfigure menus.en.toml#
This file allows you to configure the menu for your site.
In it’s simplest form the menu is built using a name and pageRef pair for each menu item. They will be displayed alphabetically but you can control the order by adding a weight option.
The example below shows a simple menu with a home link, a posts link and an about me link.
[[main]]
name = "Home"
pageRef = "index"
weight = 1
[[main]]
name = "Posts"
pageRef = "posts"
weight = 2
[[main]]
name = "Projects"
pageRef = "projects"
weight = 3
[[main]]
name = "About Me"
pageRef = "about"
weight = 4Home uses the index pageRef, this will take you to the home page of your site.
Posts links to a section called posts.
Projects links to a section called projects.
The About Me pageref links to a page called about.md. You don’t need to provide the file extension.
Your menu structure should reflect the structure of your content folder. I’ll go into detail on that later in the guide.
Configure params.toml#
This config file holds the options to configure the look and feel of your site. Blowfish is hugely flexible with way too many options to cover here but I’ll call out a few of the key settings I changed to get this site looking how I wanted it. You can view the full docs here.
Colour Scheme#
The first section is where you set the colour scheme. Blowfish has a range of built in schemes which all look great.
You can choose a default appearance of dark or light modes and enable automatic switching based on the user’s system preferences.
colorScheme = "blowfish"
defaultAppearance = "dark" # valid options: light or dark
autoSwitchAppearance = trueRecent posts#
Blowfish can highlight recent posts on the home page.
You might have a section of your site you want to exclude from this list. You can control this with the mainSections setting.
For example you might have a posts section and a projects section but only want content from posts to appear in this list. Uncomment this setting and update it to match what you want to show.
mainSections = ["posts"]Table of Contents#
These next three settings make your articles look amazing! Slightly jumping ahead here. Your articles are written in Markdown. You can use markdown headings to create section and sub-sections in your articles. In Markdown it look like this:
# This is a main heading (H1)
## This is a sub-heading (H2)
### This is a sub-sub-heading (H3)Blowfish will automatically generate a table of contents for your article based on these headings, you have to enable showing it by setting showTableOfContents = true in the [article] section of your params.toml file.
You can take this to next level of awesome by enabling highlightCurrentMenuArea = true and smartTOC = true. This moves the table of contents into a side panel and highlights the current section on the screen as you scroll through the article. It looks really professional and makes it easy for readers to navigate your content.
Home page settings#
The [homepage] section is where you configure how the home page will appear.
The most impactful setting here is layout. Blowfish has serveral built in layout options. The default is profile but you can choose page, hero, card, background or custom and create your own html and css to get exactly what you want. Experiment with these options to what suits your site best.
You can also control recents and if you want to show thumbnail card pictures for recent posts. More on that later.
Article settings.#
This section allows you to configure a default style for your articles.
Enabling control for features like showing the creation date, last date updated, author name, reading time and word count. These can all be over-ridden on a per article basis by setting front matter in your markdown files. I’ll cover that later.
Testing your site locally#
With the basic configuration complete you can now test your site locally. Hugo has a built-in server that you can use to preview your site.
In your terminal window run the following command:
hugo server --disableFastRender --noHTTPCacheThis will start the Hugo server and you should see output similar to this:
Start building sites …
hugo v0.154.5-a6f99cca223a29cad1d4cdaa6a1a90508ac1da71+extended windows/amd64 BuildDate=2026-01-11T20:53:23Z VendorInfo=gohugoio
│ EN
──────────────────┼────
Pages │ 14
Paginator pages │ 0
Non-page files │ 0
Static files │ 7
Processed images │ 2
Aliases │ 0
Cleaned │ 0
Built in 1979 ms
Environment: "development"
Serving pages from disk
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stopOpen your web browser and navigate to http://localhost:1313/ to see your site in action. You can make changes to your site files and the server will automatically reload the site to reflect your changes.
Creating and managing content#
I mentioned previously the menu structure should reflect the structure of your content. Earlier I created a menu with Home, Posts, Projects and About Me links.
To make these links work you need to create the relevant folder structure in the content folder of your project.
We don’t need to worry about the Home link as Hugo will handle that for us. Posts and Projects are sections so we need to create a folder for each section. About Me is a page link so create a markdown file called about.md.
Create them now so that your content folder looks like this:
content
├── posts
├── projects
└── about.mdOpen about.md and add some content to it. Doesn’t matter what for now as we’re going to b recreating this page soon.
Once done start the local server again with hugo server --disableFastRender --noHTTPCache and navigate to http://localhost:1313/about/ to see your about page. All being well you should see your about page with the content you just added.
So, creating content is as simple as creating files for pages and folders for sections. However there is a better way to do this using Hugo’s built-in commands, which will lead us into a discussion on archetypes and front matter.
Stop the local server by pressing Ctrl+C in the terminal window, delete the about.md file and make sure your terminal is in the root of your project folder. Run the following command:
hugo new content about.mdYou should see the about.md file has been recreated in the content folder.
Open the file and you will see it has some front matter already, but before we go into that try a few more commands:
To create a new page in the posts section run:
hugo new content posts/my-first-post.mdNow run the following command:
hugo new content posts/my-second-post/index.mdYou’ll notice that the second command created a folder called my-second-post and created an index.md file inside it.
This is another structural element to create content in Hugo. Both methods are valid and will work fine. The advantage of using the index.md method is that you can add additional files to the folder if you need to, for example images or other assets related to that post.
What about if we want to create a whole new section? Let’s create a section called tutorials. Run the following command:
hugo new content tutorials/my-first-tutorial/index.mdTo get the new tutorials section available on the homepage we need to update the menu configuration we did earlier.
Open menus.en.toml and add the following code, remembering to update the weights of the other menu items so they appear in the order you want:
[[main]]
name = "Tutorials"
pageRef = "tutorials"
weight = 3If you look in the new markdown files we’ve created you will see some text similar to this at the top of each file:
+++
date = '2026-02-02T11:21:41Z'
draft = true
title = 'About'
+++This is called front matter and it is used by Hugo to manage your content. Front matter is created based on an archetype. Archetypes are templates that define the default front matter for different types of content.
By default Hugo uses the archetypes/default.md file to create new content. You can customize this file to add additional front matter fields that you want to use in your content.
If you start the local server now none of these pages will be visible as they are all marked as drafts. You can either set draft = false in the front matter of each file or start the server with the --buildDrafts flag to see draft content.
If you open archetypes/default.md you will see the template front matter that Hugo will apply to each page you create using the CLI commands. It’ll look something like this, bearing in mind that I have switched mine to YAML format:
---
date: "{{ .Date }}"
draft: true
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
---As you can see it is using some code methods and functions to set the date and title field. There a lot more of these detailed in the Hugo documentation.
Front matter#
Front matter is incredibly powerful. You can use it control how individual pages and sections behave.
Overriding the default settings in params.toml on a page by page basis. Hugo has a comprehensive set of front matter options you can use listed in full here and Blowfish has additional theme specific front matter options to complement these listed here.
You can enter front matter in either TOML, YAML or JSON format. Persoanlly I’m more comfortable with YAML so I have updated my archetypes\default.md file to use YAML format.
Ok. Here are a few examples of front matter options you can use in your content:
Let’s say you have a page that you don’t want to include in search results, have a publication date or include a word count and reading time. You can add the following front matter to that page:
showDate: false
showReadingTime: false
showWordCount: false
draft: false
excludeFromSearch: trueAnother useful feature of front matter is the ability to set tags on your articles. In the front matter code enter
tags: ["hugo", "blowfish"]then in your menus.en.toml file set a menu item with the pageRef of tags.
[[main]]
name = "Tags"
pageRef = "tags"
weight = 6The last front matter option I want to highlight leads us nicely into the next section I want to cover. Inserting images and thumbnails into your articles.
Images and thumbnails#
Thumbnails and hero images#
Blowfish has a really easy system for adding thumbnails to your articles. It requires you to use the directory structure method of creating content instead of a single markdown file in \content\.
If you’ve been following along go to content\posts\my-second-post\ folder, paste in any image file you have and rename it to featured.png, if it’s a png of course. So your folder will now look something like this:
content
├── posts
└── my-second-post
├── featured.png
└── index.mdThe name of the file being feature* tells Blowfish this image is a featured image for this article. It will use it as a thumbnail on your site and include it as an oEmbed card if you share your article link on social media.
We can also use that image in the article itself using some front matter configuration. Open index.md and add the following front matter:
showHero: true
heroStyle: "background"This will show the image as a background image at the top of your article and by default will blur out the image as you scroll down the page. It looks great!
You can disable the blur effect by adding layoutBackgroundBlur: false to the front matter also. Valid options for heroStyle are basic, big, background and thumbAndBackground. Have a play around with the local server running to see what suits your site the best.
Great stuff, but what if you want to use the same thumbnail image for multiple articles without having to copy the image into each article folder?
This is where the assets folder comes into play.
Navigate from the project root folder into the assets folder and create a new folder named images, copy the featured.png image from content/posts/my-second-post/ into the new assets/images/ folder.
Rename it to something more generic like shared.png.
Now open content/posts/my-first-post.md. We didn’t create a folder for this page so can’t use the built-in featured image functionality. Instead we can use front matter to point to the shared image we just added. Add the following front matter to the top of the file:
featuredImage: "images/shared.png"Now if you spin up the local server again both posts should be showing the same thumbnail image.
The path to the image is relative to the assets folder. So you don’t need to include assets/ in the path.
There is a second folder in the project called static where you can store things like images you want to include in your site.
The difference between static and assets is that files in the static folder are copied as-is to the generated site when you build it. Files in the assets folder are automatically optimised by Hugo when you build the site.
If you have images that are already optimised or for whatever reason, you don’t want Hugo to process them use the static folder. For most cases using the assets folder is the best option.
Inserting images in articles#
There are a couple of options for inserting images into your pages. The first is to use standard markdown syntax:
You can also use Mardown Attributes to do things like resize the image. This code will insert an image and reduce the width by 50%.

{style="width:50%;"}Just like with with feature images they can be located with the post in a content folder or in the assets/images/ folder. They can also hosted elsewhere and linked using a URL.

Images accessed via an external URL are provided as-is. Hugo cannot optimise them automatically but you can resize them using query parameters, for example “?w=1600&h=900&fit=crop”
The second option is to use Shortcodes. A quick discussion of Shortcodes is the next, and final content related section, but I’ll show the figure shortcode here as it’s relevant to this section.
Inserting an image using a figure shortcode looks like the example below:
{{< figure
src="path/to/image.png"
alt="Alt Text"
caption="Optional Image Caption"
>}}Shortcodes#
Hugo comes with a set of default shortcodes and Blowfish enhances this with some extra theme specific shortcodes adding more functionality. You can find the full list here: here.
There are some really useful shortcodes in the Blowfish theme.
You can link to a GitHub Card:
{{< github repo="paul-mccormack/howdoyoucloud.github.io" showThumbnail=true >}}You can embed icons:
{{< icon "github" >}}{{< icon "facebook" >}}{{< icon "poo" >}}The full list of available icons is here.
There is even a shortcode that will type text for you! 🤪
{{< typeit tag="h3" speed=50 breaklines=false loop=true >}} "This is the TypeIt shortcode in action!" {{< /typeit >}}The final shortcode I want to show off will be very useful if you are a Youtuber! Blowfish has a shortcode that allows you to embed YouTube videos! 🤩
{{< youtube id="zdrzDBz_CW8" label="3D Flyover Tour Manchester City UK" >}}Site deployment and hosting on GitHub Pages#
At this stage you’ve probably got something you want to publish, even if it’s just to get a view on how the process looks.
If you have a custom domain you want to use that’s great, I’ll explain how to do that but if you don’t using the default github.io domain is a great zero cost option to get your site online.
Enable GitHub Pages#
The first thing you need to do is enable GitHub Pages for your repo.
Go to your repo, click on the settings tab, then click on Pages in the left hand menu. Under “Build and Deployment” select “GitHub Actions” as the source.
Create a GitHub Actions workflow#
Next we need to create a workflow to enable GitHub Actions to build and deploy the site.
In the root of your project folder create a new folder called .github and inside that create a another folder called workflows. Inside the workflows folder create a new file called hugo.yaml.
The name of the file doesn’t matter but it’s good practice to name it something relevant to what it does. Your folder structure should now look like this:
.github
├── workflows
└── hugo.yamlPaste the following code into the yaml file:
name: Deploy Hugo site to GitHub Pages
on:
# This will trigger the workflow on pushes to the main branch.
push:
branches:
- main
# This allows you to manually trigger the workflow from the GitHub Actions tab in your repository.
workflow_dispatch:
# Sets permissions for the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
# Default to bash
defaults:
run:
shell: bash
jobs:
# Install dependencies and build the site
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.160.1 # Latest version - check this and update as needed.
HUGO_ENVIRONMENT: production
TZ: Europe/London
steps:
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
- name: Install Node.js dependencies
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- name: Cache Restore
id: cache-restore
uses: actions/cache/restore@v4
with:
path: |
${{ runner.temp }}/hugo_cache
key: hugo-${{ github.run_id }}
restore-keys:
hugo-
- name: Configure Git
run: git config core.quotepath false
- name: Build with Hugo
run: |
hugo \
--gc \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/" \
--cacheDir "${{ runner.temp }}/hugo_cache"
- name: Cache Save
id: cache-save
uses: actions/cache/save@v4
with:
path: |
${{ runner.temp }}/hugo_cache
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
# Deploy the site to GitHub Pages
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4This workflow will run when you push changes to the main branch of the remote repository.
You can also find a copy of this file in my repo for this site here
If you ever want to push some changes to GitHub but don’t want to trigger the workflow you can add [skip ci] to your commit message and GitHub Actions will ignore that commit.
Build and deploy the site#
We are now at the point where we can build and deploy the site.
If you have been comitting and pushing your changes to GitHub as you followed along, including adding the new workflow file without adding a [skip ci] tag you’ve probably already triggered the action and your site is now live!.
If not you’ve got two options to trigger the workflow:
- You can make a small change to your site files and push that to main, or if you haven’t pushed since the initial one just do it now.
- You can trigger the workflow manually from the Actions tab in your GitHub repo. Click on the workflow you want to run and click the “Run workflow” button.
Whichever option you choose do that now.
The workflow should only take a few minutes and you can monitor it from the Actions tab in your GitHub repo. When it completes you will see the URL on the “deploy” job in the workflow run summary.
Alternatively go to Settings then Pages in your repo and you will have a visit site button. You can also get the default URL from this screen.
Adding a Custom Domain#
If you have a custom domain you want to use set-up is fairly straightforward.
You will need to be able to create DNS records for your domain to verify ownership and point to the GitHub Pages hosted site. The exact steps for this will depend on your DNS provider but the process is generally like this:
Prove ownership of the domain. Go to your GitHub account settings and click on Pages in the left hand menu. You will be presented with the option to add a “Verified domain”. This process involves GitHub providing you with a TXT record to add to your DNS zone. Once you have done that they will check it exists and you have successfully verfied you own the domain. There might be a bit of a delay in this process as DNS changes can take time to propagate.
You now need to create some DNS records to point to the site on GitHub Pages.
Create the following A records and CNAME record in your DNS zone:
Type: A
Name: @ (This should create a record at the domain apex)
Value: 185.199.111.153
Type: A
Name: @ (This should create a record at the domain apex)
Value: 185.199.110.153
Type: A
Name: @ (This should create a record at the domain apex)
Value: 185.199.109.153
Type: A
Name: @ (This should create a record at the domain apex)
Value: 185.199.108.153
Type: CNAME
Name: www
Value: <your-repo-name>.github.io (For the example in this guide it would be mynewsite.github.io)- The last step is to add the custom domain to your GitHub Pages settings. Go back to Settings tab in your repo and then to the Pages menu. Under “Custom domain” enter your domain name and click “Save”. GitHub will check the DNS records are all set-up correctly and all being well You should see a green tick with a message saying “DNS check successful”. Make sure you also tick the “Enforce HTTPS” box. GitHub will provide you with a free managed SSL certificate. With that part complete the site is now live on your custom domain!
Go and check it works! 😀
Wrapping up#
That was a long one but hopefully you now have an understanding of how Hugo with the Blowfish theme allow you to create a really good looking static web site with really not much work at all.
I love how you can create content in Markdown and Hugo takes care of all the HTML and CSS for you. The Blowfish theme has an outstanding set of features and configuration options!
I’ve got a couple of pages set-up on the site to use as cheatsheets for both Hugo and Blowfish. As I discover more useful features and just generally get more comfortable working with these tools I’ll post it up those pages. Click the links below to see them:
