Hugo Tutorial: Building a Blog From Scratch in 30 Minutes

Hugo Tutorial: Building a Blog From Scratch in 30 Minutes

Hugo tutorial: a step-by-step guide to building a blog from scratch. Installing Hugo, picking a theme, configuration, deployment. A complete beginner's guide in 30 minutes.

When I decided to start a blog, the first thing I did was look at website builders. Craftum, Tilda, Wix — they all look nice, but for a developer’s blog that’s like using a microscope to hammer in nails. Then I tried WordPress and nearly went gray from the sheer number of plugins and vulnerabilities. In the end I found Hugo, and it was the best decision I made.

In this tutorial I’ll show you how to build a blog on Hugo from scratch in 30 minutes. No fluff, just practice.

Why Hugo Instead of WordPress or a Website Builder

Before installing anything, let’s figure out why Hugo specifically.

Build speed — Hugo builds sites faster than anything else. Seriously, thousands of pages in seconds. Jekyll, Gatsby, Next.js aren’t even close.

No database — all your content lives in Markdown files. No MySQL, no SQL injection vulnerabilities, no database backups. Everything lives in Git.

Markdown — you write posts in your favorite editor (Obsidian, VS Code, even vim). No browser-based WYSIWYG editors.

Hosting is nearly free — a static site can be hosted on GitHub Pages, Netlify, or Vercel. Free and fast.

Full control — want to change something in the theme? Just edit the files. No “only available in the Pro version.”

By the way, I wrote in detail about why I moved from a website builder to Hugo in Hugo vs Craftum . That post covers the pain of using website builders for a blog.

Installing Hugo

macOS

# Via Homebrew (recommended)
brew install hugo

# Verify
hugo version

Linux (Ubuntu/Debian)

# Snap — the simplest way
sudo snap install hugo --channel=extended

# Or via apt (may be an older version)
sudo apt install hugo

# Verify
hugo version

Windows

# Via Chocolatey
choco install hugo-extended

# Or via Scoop
scoop install hugo-extended

# Verify
hugo version

Important: install hugo-extended specifically, not just hugo. The extended version supports SCSS and other features that most themes need.

Creating a New Site

# Create the project
hugo new site my-blog

# Move into the folder
cd my-blog

# Initialize Git (required for themes)
git init

Project structure:

my-blog/
├── archetypes/     # Templates for new posts
├── assets/         # SCSS, JS (processed by Hugo)
├── content/        # Your content (posts, pages)
├── data/           # Data in JSON/YAML/TOML
├── i18n/           # Translations
├── layouts/        # Custom templates
├── static/         # Static files (images, CSS, JS)
├── themes/         # Themes
└── hugo.toml       # Main config

Choosing and Installing a Theme

Themes account for 90% of how your blog looks. Head over to themes.gohugo.io and pick one.

My recommendations for a developer blog:

  • PaperMod — minimalist, fast, popular
  • Congo — modern, with a dark theme
  • Blowfish — good-looking, lots of settings
  • Nightfall — what I use myself

Install the theme as a git submodule:

# PaperMod
git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod

# Or Congo
git submodule add https://github.com/jpanther/congo.git themes/congo

# Or Nightfall (my theme)
git submodule add https://github.com/LordMathis/hugo-theme-nightfall.git themes/nightfall

Configuring the Site

Open hugo.toml and configure it:

baseURL = 'https://yourdomain.com/'
languageCode = 'en'
title = 'My Blog'
theme = 'PaperMod'  # Theme folder name

[params]
  author = "Your name"
  description = "A blog about programming and technology"
  
  # For PaperMod
  showReadingTime = true
  showShareButtons = true
  showPostNavLinks = true
  
[menu]
  [[menu.main]]
    name = "Blog"
    url = "/posts/"
    weight = 1
  [[menu.main]]
    name = "About"
    url = "/about/"
    weight = 2

# SEO
[markup]
  [markup.goldmark]
    [markup.goldmark.renderer]
      unsafe = true  # Allows HTML in Markdown

Every theme has its own set of parameters — check the theme’s documentation.

Writing Your First Post

# Create a post
hugo new posts/my-first-post/index.md

Hugo will create a file with basic frontmatter. Let’s edit it:

---
title: "My First Post"
date: 2025-01-31
description: "SEO description of the post, 150-160 characters"
tags:
  - hugo
  - blog
---

Hello, world! This is my first Hugo post.

## Second-Level Heading

Post body text. Full **Markdown** is supported:
- lists
- *italics*
- `code`

### Syntax-Highlighted Code

```go
package main

import "fmt"

func main() {
    fmt.Println("Hello, Hugo!")
}

Images

Put an image in the post’s folder and insert it:

Image description


### Post Structure (Page Bundles)

Hugo supports two ways of organizing posts:

**1. Standalone files:**

content/posts/ ├── my-first-post.md ├── second-post.md


**2. Page Bundles (recommended):**

content/posts/ ├── my-first-post/ │ ├── index.md │ └── image.webp ├── second-post/ │ ├── index.md │ └── screenshot.png


Page Bundles are more convenient — images live right next to the post instead of in a shared `static/` folder.

## Local Server

```bash
# Start the development server
hugo server -D

# -D shows drafts (draft: true)

Open http://localhost:1313 and you’ll see your blog. The server automatically reloads the page whenever you make changes — very convenient.

Building for Production

# Build the site
hugo

# Or with minification
hugo --minify

The finished site will show up in the public/ folder. These are static HTML/CSS/JS files that you can host anywhere.

Deploying to GitHub Pages

The easiest way to host a blog for free.

1. Create a Repository

Create a repository named username.github.io on GitHub.

2. Push Your Code

git add .
git commit -m "Initial commit"
git remote add origin git@github.com:username/username.github.io.git
git push -u origin main

3. Set Up GitHub Actions

Create .github/workflows/hugo.yml:

name: Deploy Hugo site

on:
  push:
    branches: [main]

jobs:
  build-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true  # For themes added as submodules
          
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'
          extended: true
          
      - name: Build
        run: hugo --minify
        
      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

4. Enable Pages

In the repository settings: Settings → Pages → Source: gh-pages branch.

A couple of minutes later your blog will be live at https://username.github.io.

Deploying to Your Own Server

If you want full control, deploy to a VPS. I use GitLab CI/CD:

# .gitlab-ci.yml
stages:
  - build
  - deploy

build:
  stage: build
  image: registry.gitlab.com/pages/hugo:latest
  script:
    - hugo --minify
  artifacts:
    paths:
      - public

deploy:
  stage: deploy
  script:
    - rsync -avz public/ user@server:/var/www/blog/
  only:
    - main

I wrote more about automation and CI/CD for developers in my post about Cursor AI — that one covers automating the routine stuff.

Useful Hugo Commands

# Create a new post
hugo new posts/article-name/index.md

# Local server with drafts
hugo server -D

# Build
hugo --minify

# Build including future posts
hugo --minify --buildFuture

# List all posts
hugo list all

# Check the config
hugo config

SEO Optimization

Out of the box, Hugo generates:

  • sitemap.xml — a sitemap
  • an RSS feed
  • a proper URL structure

For full SEO optimization, add to your templates:

  • Open Graph tags
  • Twitter Cards
  • Schema.org markup
  • Canonical URLs

If you’re curious how I optimized this blog for SEO, let me know and I might write a separate post about it.

Common Problems

The Theme Isn’t Applied

# Check that the theme is specified in the config
cat hugo.toml | grep theme

# Check that the theme folder exists
ls themes/

Images Aren’t Showing Up

Use Page Bundles and relative paths:

![alt](image.webp)  # If the image is in the post's folder

The Server Isn’t Picking Up Changes

# Restart the server
hugo server -D --disableFastRender

“TOCSS: failed to transform” Error

You need the extended version of Hugo:

hugo version  # Should say "extended"

Conclusion

Hugo is a tool for people who want to control their own blog. No dependency on website builders, no monthly payments, no lag.

What to do next:

  1. Install Hugo and create your first post
  2. Pick a theme that fits your style
  3. Set up deployment via GitHub Actions or GitLab CI
  4. Write content and don’t sweat the technical details

If you want to learn about productivity when writing posts, check out time management techniques for developers .


Have questions about Hugo? Leave a comment or reach out on Telegram — happy to help.