Hugo is one of the most popular frameworks for creating JAM stack websites easily. It is powering thousands of websites as well as complex applications at the moment. Due to its high performance, it is almost overtaking wordpress deployments. This blog post explains how you can deploy a simple Hugo website using Github Actions and Github pages for free.
Hugo Overview
Hugo is a highly popular open-source static site generator (SSG) designed to create fast and flexible websites. Developed in the Go programming language, Hugo aims to simplify the process of building static websites by allowing developers to generate web pages from simple text files.
Unlike traditional content management systems (CMS) that dynamically render web content on each request, Hugo generates static HTML files during the build process. This makes the resulting website extremely fast, secure, and easy to host on any web server or content delivery network (CDN). It offers support for multi-language sites, powerful templating with reusable components, live-reloading for instant previews during development, and a vast ecosystem of themes and plugins created by a vibrant community.
Whether you’re building a personal blog, documentation site, portfolio, or e-commerce store, Hugo provides an efficient and scalable solution for generating static websites that are both visually appealing and performant.
Setup Project Directory
Let’s set up our project repository.
Prerequisites
- Hugo website
- Git
This post assumes that you already have a Hugo website ready to deploy.
If you’re using Github for your repository hosting, you can create a repository with name <username>.github.io. This is special name that Github pages use to host your website. This repo will be accessible at the URL https://<username>.github.io once it’s deployed. Go inside your Hugo website directory and follow below commands to set up your Github repo.
git init
git remote add origin git@github.com:<username>/<repo-name>
git add .
git commit -m "Initial Hugo website"
git push origin master
With above setup done, you should have a repository with name <username>.github.io in your Github account.
In your Github account, for the repository, change the visibility to public repository if it’s not public. Go to Seetings > Danger Zone > Change Visiblity > Change to public
Also change the Page source by going to “Settings > Pages” and set the “Source” to “Github Actions”.
What is Github Actions?
GitHub Actions is a flexible automation framework built into the GitHub platform that allows you to define custom workflows for your software projects. With this feature, developers can automate common tasks, build, test, and deploy their applications directly from their GitHub repositories. It empowers developers to create complex workflow pipelines without relying on external tools or services.
Building Blocks:
Workflow: A workflow represents an automated process consisting of one or more jobs performed on specific events or triggers. Workflows are defined using YAML files and can be customized to suit your project’s needs.
Jobs: Jobs are units of work within a workflow that run in parallel by default and define the sequence of steps required to accomplish a specific task. Each job runs on its own virtual environment (runner) and can include multiple steps.
Steps: Steps are the individual actions that make up a job. They represent tasks like building, testing, deploying, or sending notifications. You can use both built-in actions provided by GitHub or create your own custom actions for specific requirements.
Actions: Actions are reusable building blocks used within workflows to perform various tasks within your development process. You can leverage pre-built actions from the GitHub Marketplace, community-maintained repositories, or create your own custom actions.
Create a file .github/workflows/github-pages.yml in your repository.
We first specify the general syntax for Github actions. These at least includes name and we also provided some default.
1name: Build & Deploy Site
2defaults:
3 run:
4 shell: bash
Next, specify when the workflow should run.
1on:
2 workflow_dispatch:
3 push:
4 branches:
5 - main
At high level, we have two jobs. One for setting up hugo and building the website and another for deploying the website to Github pages.
1jobs:
2######################################################################
3# build & deploy the site
4######################################################################
5 build:
6 name: Build and deploy
7 if: "!contains(github.event.head_commit.message,'[skip-ci]')"
8 runs-on: ubuntu-latest
9 ... ...
10 ... ...
11 # Deployment job
12 deploy:
13 environment:
14 name: github-pages
15 url: ${{ steps.deployment.outputs.page_url }}
16 runs-on: ubuntu-latest
17 needs: build
18 ... ...
19 ... ...
In above code, we specify that both steps run on ubuntu-latest using runs-on and the second job deploy depends on build job using needs: build.
Let’s go deeper into each job in detail.
The build job has several steps which include checking out repository, downloading and installing hugo on our pipeline runner instance. Next we install dart-sass so that we can process sass files. We set up Github Pages, build the website using hugo command and upload the artifacts from ./public directory for Github pages.
1 build:
2 name: Build and deploy
3 if: "!contains(github.event.head_commit.message,'[skip-ci]')"
4 runs-on: ubuntu-latest
5 steps:
6 - name: Checkout repo codebase
7 uses: actions/checkout@v3
8 with:
9 submodules: recursive
10 fetch-depth: 0
11 - name: Download Hugo v${{ env.HUGO_VERSION }} and Install
12 env:
13 HUGO_VERSION: 0.115.3
14 run: |
15 wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
16 && sudo dpkg -i ${{ runner.temp }}/hugo.deb
17 - name: Install Dart Sass
18 run: sudo snap install dart-sass
19 - name: Setup Pages
20 id: pages
21 uses: actions/configure-pages@v3
22 - name: Build with Hugo
23 env:
24 # For maximum backward compatibility with Hugo modules
25 HUGO_ENVIRONMENT: production
26 HUGO_ENV: production
27 run: |
28 hugo \
29 --gc \
30 --minify \
31 --baseURL "${{ steps.pages.outputs.base_url }}/"
32 - name: Upload artifact
33 uses: actions/upload-pages-artifact@v1
34 with:
35 path: ./public
Next, the deploy job includes deploying the website to Github pages.
1 deploy:
2 environment:
3 name: github-pages
4 url: ${{ steps.deployment.outputs.page_url }}
5 runs-on: ubuntu-latest
6 needs: build
7 steps:
8 - name: Deploy to GitHub Pages
9 id: deployment
10 uses: actions/deploy-pages@v2
The complete file looks like below.
1name: Build & Deploy Site
2defaults:
3 run:
4 shell: bash
5# When the action should run?
6# Here, we specify workflow should run on push to main branch
7# We also specified it to run manually with empty "workflow_dispatch"
8on:
9 workflow_dispatch:
10 push:
11 branches:
12 - main
13
14# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
15permissions:
16 contents: read
17 pages: write
18 id-token: write
19# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
20# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
21concurrency:
22 group: "pages"
23 cancel-in-progress: false
24
25
26jobs:
27######################################################################
28# build & deploy the site
29######################################################################
30 build:
31 name: Build and deploy
32 if: "!contains(github.event.head_commit.message,'[skip-ci]')"
33 runs-on: ubuntu-latest
34 steps:
35 ######################################################################
36 # checkout full codebase
37 ######################################################################
38 - name: Checkout repo codebase
39 uses: actions/checkout@v3
40 with:
41 submodules: recursive
42 fetch-depth: 0
43 ######################################################################
44 # download & install Hugo (line break added in URL for readability)
45 ######################################################################
46 - name: Download Hugo v${{ env.HUGO_VERSION }} and Install
47 env:
48 HUGO_VERSION: 0.115.3
49 run: |
50 wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
51 && sudo dpkg -i ${{ runner.temp }}/hugo.deb
52 - name: Install Dart Sass
53 run: sudo snap install dart-sass
54 - name: Setup Pages
55 id: pages
56 uses: actions/configure-pages@v3
57 - name: Build with Hugo
58 env:
59 # For maximum backward compatibility with Hugo modules
60 HUGO_ENVIRONMENT: production
61 HUGO_ENV: production
62 run: |
63 hugo \
64 --gc \
65 --minify \
66 --baseURL "${{ steps.pages.outputs.base_url }}/"
67 - name: Upload artifact
68 uses: actions/upload-pages-artifact@v1
69 with:
70 path: ./public
71
72 # Deployment job
73 deploy:
74 environment:
75 name: github-pages
76 url: ${{ steps.deployment.outputs.page_url }}
77 runs-on: ubuntu-latest
78 needs: build
79 steps:
80 - name: Deploy to GitHub Pages
81 id: deployment
82 uses: actions/deploy-pages@v2


Comments