Originally published on Off on a tangent.
Here is how to get a fast, free, and low-maintenance blog up and running using Hugo—based on the exact steps I took to build my new site.
What is Hugo?
Hugo is one of the fastest open-source static site generators available. Instead of querying a database and rendering pages on the fly on every request like traditional CMS platforms, Hugo takes your Markdown files, applies HTML templates, and compiles your entire site into static HTML, CSS, and JavaScript in milliseconds.
Even better: Hugo is written in Go (Golang), which is currently my favourite programming language! Because it's built in Go, Hugo ships as a single, dependency-free binary with blazing-fast build times and rock-solid tooling. If you're a fellow Go fan—or curious to see what a large, high-performance real-world Go codebase looks like—I highly recommend checking out the Hugo source code on GitHub.
1. Initializing the Site & Adding a Theme
Once you have Hugo installed, scaffolding a new site and initializing Git takes just a few commands:
hugo new site blog cd blog git init Rather than copying theme files directly into the project, adding your theme as a Git submodule makes it easy to pull upstream updates later without cluttering your repository history. For my blog, I used the Rusty Typewriter theme:
git submodule add https://github.com/math-queiroz/rusty-typewriter themes/rusty-typewriter 2. Configuring hugo.toml and Client-Side Search
Your site's global settings live in hugo.toml. Beyond setting your baseURL, title, and author details, this is where you configure menus, taxonomies, and theme parameters.
Rusty Typewriter also includes built-in client-side search powered by FlexSearch. To enable it, you configure Hugo to output a searchindex.json file at build time alongside the standard HTML and RSS outputs:
baseURL = 'https://tangent-labs.co.za/' locale = 'en-US' title = 'Off on a tangent' theme = 'rusty-typewriter' [rusty_typewriter] [params.rtwt] sidePane = true countPageItems = 7 searchPath = 'search' [params.rtwt.home] showBio = true showAuthorImg = false sidePaneTags = true showFeatured = true showRecent = true hideRecentWhenFeatured = true countRecent = 5 [params.rtwt.side.home] sidePaneSticky = false taxonomies = ['tags'] countTaxonomy = 6 [params.rtwt.side.list] sidePaneSticky = false [params.rtwt.side.single] sidePaneSticky = true showDetails = true showTableOfContents = true showAttachments = true showRelated = true countRelated = 5 [related] includeNewer = true [[related.indices]] name = 'tags' weight = 100 [taxonomies] tag = 'tags' [params] summaryLength = 1 dateFormat = '2 Jan 2006' searchLimit = 10 [params.author] name = 'Keanu Dirkse' [params.links] hugo = 'https://gohugo.io/' theme = 'https://github.com/math-queiroz/rusty-typewriter' [[menus.main]] name = 'Posts' pageRef = '/posts' weight = 1 [[menus.main]] name = 'About' pageRef = '/about' weight = 2 [outputFormats] [outputFormats.SearchIndex] mediaType = 'application/json' baseName = 'searchindex' isPlainText = true notAlternative = true [mediaTypes] [mediaTypes.'application/json'] suffixes = ['json'] [outputs] home = ['HTML','RSS','SearchIndex'] Tip on Go Date Formatting: Notice
dateFormat = '2 Jan 2006'. Because Hugo uses Go'stimepackage under the hood, layouts are formatted using Go's reference time (Mon Jan 2 15:04:05 MST 2006) rather thanYYYY-MM-DDtokens.
Home Page Data & Static Pages
For the Rusty Typewriter home page bio, create data/rtwt/content.yaml:
home: greetings: 'Off on a tangent' text: 'Notes and experiments from Tangent Labs.' And create an About page at content/about.md (make sure to include a date in the front matter so the search index doesn't fall back to 1 Jan 0001):
+++ title = 'About' date = 2026-11-11T18:00:00+02:00 type = 'blank' +++ # About Hi, I'm Keanu Dirkse. This is where I write about things I'm building and learning. You can now preview your site locally with live reload by running:
hugo server -D Continue Reading on My Blog
That covers the initial local setup! In the full article on my blog, I walk through the rest of the production setup and day-to-day workflow, including:
- Locking down
.gitignoreso build artifacts and service account keys never get committed - Configuring Firebase Hosting for static Hugo sites (and why you shouldn't enable SPA mode)
- Automating builds and deployments on every push to
mainusing GitHub Actions - Day-to-day commands for writing posts, previewing drafts, and updating theme submodules


