Featured image showing the blog-building flow: writing in Notion → converting to Markdown → building with Hugo → deploying to GitHub Pages

Introduction

I had been keeping technical notes in Evernote and personal documents, and was preparing to run a blog using Notion’s website feature.

However, Notion had limitations on customization, and using a custom domain came with extra costs, which gave me pause.

As an alternative, I considered switching to velog or rewriting everything in Markdown and moving to Jekyll.

But I couldn’t give up Notion, which is so convenient to write in. My conclusion: write in Notion and deploy it as a static website!

Goals

  • Build documents written as md files with Hugo
  • Automate deployment with GitHub Pages

💡 Build Environment

  • Test environment: Mac
  • Deployment environment: GitHub Actions

Why I Chose Hugo

  • Has a large number of GitHub stars and is actively updated
  • Faster than Jekyll when building over 1,000 pages

This blog currently runs on the following flow. (Source reference: )

Write in Notion
→ Convert to Markdown via the Notion API

→ Build a static site with Hugo

→ Deploy to GitHub Pages

Preparation

Choosing a Hugo Theme

I first picked a theme from Hugo Themes.

Chosen theme: m10c

Theme selection criteria

  • Supports SEO optimization features
  • Supports multilingual site features

Some features aren’t fully supported in m10c, but this can be addressed with Hugo’s layout overrides.

Installing Hugo

Installation docs: Installation Guide

Hugo docs: Documentation

Mac example

1# Install Hugo
2brew install hugo
3
4# Verify installation
5hugo --version

Creating a Hugo Site

Initializing the Project

 1# Create a working directory
 2mkdir hugo && cd hugo
 3
 4# Create a Hugo site
 5hugo new site .
 6
 7# Check the result
 8tree
 9# .
10# ├── archetypes
11# │   └── default.md
12# ├── assets
13# ├── content
14# ├── data
15# ├── hugo.toml
16# ├── i18n
17# ├── layouts
18# ├── static
19# └── themes

Installing the Theme

Install the theme using a Git submodule.

1# Initialize the Git repository (if needed)
2git init
3
4# Add the theme submodule
5git submodule add https://github.com/vaga/hugo-theme-m10c.git themes/m10c
6
7# Verify installation
8ls -al themes/m10c

Copying Sample Content (Optional)

1# Copy the theme's sample content
2cp -R themes/m10c/exampleSite/content ./content
3
4# Check
5ls -al ./content/

Hugo Configuration

Replace the default hugo.toml config file with the theme’s sample configuration.

1# Delete the existing configuration
2rm hugo.toml
3
4# Copy the sample configuration
5cp themes/m10c/exampleSite/config.toml ./hugo.toml

Open the hugo.toml file and edit the basic settings.

1baseURL = "https://testblog.plzhans.com"
2title = "Test blog"
3theme = "m10c"

Note: Remove the themesDir setting, and make sure theme matches the actual directory name.

Running the Local Server

1# Start the development server
2hugo server -D

Example output:

1Watching for changes in /Users/plzhans/temp/sample/hugo/...
2Start building sites 
3hugo v0.154.5+extended+withdeploy darwin/arm64 BuildDate=2026-01-11T20:53:23Z
4
5Built in 2 ms
6Environment: "development"
7Web Server is available at http://localhost:57264/
8Press Ctrl+C to stop

Open the address shown in your browser to check the result.

http://localhost:57264

Deploying to GitHub Pages

Creating a Repository

Create a new repository on GitHub.

Choosing a Deployment Strategy

Both Jekyll and Hugo manage source and build output separately.

Jekyll is automatically detected and deployed by GitHub Pages, but Hugo must be deployed directly through GitHub Actions.

When choosing a deployment strategy, pay attention to whether the source repository is public or private.

If you want the source repository to be private, keep the following in mind.

Free plan

  • Only public repositories can enable Pages.
  • So if you want to keep the source private, use Method 3 to keep the source repository private while making only the deployment repository public.

Paid plan

  • Pages can be public even if the repository is private.

Method 1: actions/deploy-pages

  • Uses 1 repository
  • Set the GitHub Pages source to GitHub Actions
  • Push to the main branch → Hugo build → upload artifact → automatic deployment

Method 2: peaceiris/actions-gh-pages

  • Uses 1 repository
  • Connect GitHub Pages to the gh-pages branch
  • Push to the main branch → Hugo build → commit to the gh-pages branch

Method 3: Separate Deployment Repository

  • Uses 2 repositories (source repository, deployment repository)
  • Push the build output to the deployment repository

Method 4: Uploading Build Output Elsewhere

  • You don’t have to use GitHub Pages.
  • You can simply upload the build output to a directory connected to a web server.
  • By default, the output is generated in the /public directory.

This document uses Method 1 to establish the deployment strategy.

Configuring GitHub Pages

Repository → Settings → Pages → set Source to GitHub Actions

Writing the GitHub Actions Workflow

Create a .github/workflows/deploy-hugo.yml file.

 1name: Deploy Hugo
 2
 3on:
 4  push:
 5    branches: [ master ]
 6   
 7permissions:
 8  contents: read
 9  pages: write
10  id-token: write
11
12concurrency:
13  group: pages
14  cancel-in-progress: true
15
16env:
17  HUGO_BASEURL: https://plzhans.github.io/hugo-sample/
18
19jobs:
20  build-and-deploy:
21    runs-on: ubuntu-latest
22    env:
23      HUGO_CACHEDIR: /tmp/hugo_cache
24
25    steps:
26      - name: Checkout
27        uses: actions/checkout@v4
28        with:
29          submodules: recursive
30          fetch-depth: 1
31
32      - name: Setup Hugo
33        uses: peaceiris/actions-hugo@v3
34        with:
35          hugo-version: "latest"
36          extended: true
37
38      - name: Cache Hugo
39        uses: actions/cache@v4
40        with:
41          path: $ env.HUGO_CACHEDIR 
42          key: $ runner.os -hugomod-$ hashFiles('**/go.sum') 
43          restore-keys: |
44            $ runner.os -hugomod-
45
46      - name: Build
47        run: hugo --minify --gc --cleanDestinationDir --baseURL "$HUGO_BASEURL"
48
49      - uses: actions/upload-pages-artifact@v3
50        with:
51          path: ./public
52
53      - uses: actions/deploy-pages@v4

Deploying with Git

 1# Add the remote repository
 2git remote add origin [email protected]:plzhans/hugo-sample.git
 3
 4# Set up .gitignore
 5echo "/public/" >> .gitignore
 6
 7# Commit all files
 8git add . 
 9git commit -m "first commit"
10
11# Create the branch and push
12git branch -M master
13git push -u origin master

Verifying the Deployment

Check the workflow run under the GitHub Actions tab, and check the deployed URL under Settings → Pages.

Example address: https://plzhans.github.io/hugo-sample/

Notes

baseURL configuration

If the baseURL in hugo.toml or the --baseURL option at build time is incorrect, the CSS and image paths will be wrong and errors will occur.

In this guide, the deployment address is set via the HUGO_BASEURL environment variable in the GitHub Actions workflow.