web

Deploying Hugo Sites On Github Pages

Hosting a blazing fast static site shouldn't require complex server management or expensive hosting fees. By combining Hugo, an ultra fast static site generator written in Go, with GitHub Pages, you g

Deploying Hugo Sites On Github Pages
In this story

Hosting a blazing-fast static site shouldn't require complex server management or expensive hosting fees. By combining Hugo, an ultra-fast static site generator written in Go, with GitHub Pages, you get a free, version-controlled, and globally distributed hosting pipeline.

Unlike the generic tutorials that leave out crucial details about git submodules, theme subdirectories, and automation errors, this guide walks you through the exact workflow needed to publish your site cleanly. You'll learn how to separate your source repository from your compiled static assets, automate builds using GitHub Actions, and avoid common deployment traps that break static routing.

Preparing Your Hugo Project Locally

Before touching GitHub, your local environment needs a properly structured Hugo project. If you've already initialized your site, skip to the repository separation step. If you're starting fresh, open your terminal and run the core setup commands:

  1. Install Hugo on your system using your package manager of choice (such as Homebrew on macOS, Chocolatey on Windows, or apt on Linux). Verify the installation by running hugo version.
  2. Create a new site skeleton by running hugo new site my-site-name in your working directory.
  3. Move into the new directory (cd my-site-name) and initialize a Git repository using git init.

One common mistake developers make is dropping themes directly into the themes/ directory as standard folders. If you plan to track your theme via Git, you should add it as a Git submodule so your repository tracks the reference cleanly rather than treating theme files as loose, untracked changes.

Add a theme using submodule integration:

git submodule add https://github.com/thegeeklab/hugo-hello-friend-ng.git themes/hello-friend-ng

Open your hugo.toml (or config.toml) file and make sure your baseURL matches your final production URL format. If you're deploying to a project page (e.g., username.github.io/repository-name/), your baseURL must include the subpath: [https://username.github.io/repository-name/](https://username.github.io/repository-name/). If you're using a custom domain or a user root page (username.github.io), set it to the root domain.

Structuring Repositories for Automated Builds

There are two primary ways to deploy Hugo to GitHub Pages: pushing the generated public/ folder manually, or using GitHub Actions to build the site automatically on every push. Automated builds via GitHub Actions are vastly superior because you only commit your raw source markdown and templates, letting GitHub's runners handle the compilation step.

To set up this workflow, you need two distinct branches or a dedicated repository structure. The standard approach uses a single repository where your main branch holds your source code, and GitHub Actions automatically compiles and publishes the output to a orphan gh-pages branch.

Create your initial commit and push your source code to GitHub:

git add .
git commit -m "chore: initial Hugo site setup"
git branch -M main
git remote add origin https://github.com/your-username/your-repo-name.git
git push -u origin main

Configuring GitHub Actions for Hugo

GitHub Actions removes the manual chore of running hugo locally and pushing compiled HTML. Instead, every time you write a new blog post and push it to main, GitHub builds the site for you.

Create a directory path in your project root at .github/workflows/ and create a file named gh-pages.yml. Populate it with a tested workflow configuration:

name: Deploy Hugo site to GitHub Pages

on:
  push:
    branches:
      - main

permissions:
  contents: write
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: 'latest'
          extended: true

      - name: Build Hugo Site
        run: hugo --minify

      - name: Upload Artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./public

  deploy:
    needs: build
    runs-on: GitHub-pages
    environment:
      name: GitHub-pages
      url: ${{ steps.deployment.outputs.page_url }}
    permissions:
      pages: write
      id-token: write
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

This workflow checks out your code with submodules intact, installs the Hugo extended edition (required for modern themes utilizing Sass/SCSS pipes), minifies your output assets, and uploads them to the GitHub Pages environment.

🔗 Read more: this story

Adjusting GitHub Repository Settings

With your workflow file in place, you must configure your repository permissions on GitHub to allow the action to publish.

  1. Navigate to your repository on GitHub and click on the Settings tab.
  2. In the left sidebar, click on Pages.
  3. Under the Build and deployment section, locate the Source dropdown menu and change it from Deploy from a branch to GitHub Actions.
  4. Save your changes.

Push your gh-pages.yml file to your main branch. Go to the Actions tab in your repository to watch the pipeline execute. Within a minute, your build should pass, and your static site will be live at your designated URL.

Common Deployment Pitfalls and How to Fix Them

Even with a clean workflow, developers frequently run into specific snags during deployment.

  • Broken Theme Styling: If your site builds successfully but renders as plain text without CSS, your theme wasn't cloned correctly. Ensure your action workflow includes submodules: recursive under the checkout step. Without this flag, GitHub's runner pulls an empty theme folder.
  • Incorrect Asset Paths: If images or stylesheets return 404 errors, your baseURL in hugo.toml likely mismatch your deployment path. Double-check trailing slashes and subdirectories.
  • Extended Hugo Features Failing: If your theme throws compilation errors about Sass or asset pipelining, make sure your workflow installs the extended version of Hugo rather than the standard binary.

Frequently Asked Questions

Can I use a custom domain with this setup?

Yes. Create a file named CNAME inside your static/ directory containing only your custom domain name (e.g., [www.example.com](https://www.example.com)). Hugo will copy this file to the root of your public/ directory during build time, allowing GitHub Pages to serve your site under your custom domain automatically.

Why do I need the Hugo extended version?

Many modern Hugo themes rely on Go templates combined with Sass or SCSS transpilation. The standard Hugo binary lacks the built-in Dart Sass libraries required to compile these style sheets, resulting in build failures.

How do I handle drafts when writing posts?

By default, Hugo ignores content files marked with draft = true in their front matter. If you want to preview drafts locally, run hugo server -D. When your GitHub Action builds the site for production, drafts are automatically omitted unless you explicitly override the command.

What happens if my GitHub Action build fails?

Navigate to the Actions tab in your GitHub repository to inspect the build logs. The error traceback will point directly to the misconfigured template, missing front matter variable, or invalid syntax causing the crash. Fix the issue locally, commit, and push again to re-trigger the pipeline.

CR

Written by

Chloe Ramirez

Chloe Ramirez excels at making complicated information accessible, turning dense research into clear narratives that engage diverse audiences.

More from web