building this site in go
Building this site in Go: why I wouldn't use a static-site generator
This site is a Go program. Not a Hugo/11ty/Astro setup, not a framework — a
few hundred lines of Go that reads markdown, renders it to HTML with
goldmark, and serves it. People ask why, and the honest answer is that it
turned out to be less work, not more, for the kind of site I wanted. This is
the reasoning, and the parts where that choice pays off (and where it costs).
What the site actually is
- A handful of long-form posts, an about page, a feed. No comments, no e-commerce, no 40 components.
- The content is markdown in a git repo. That's the source of truth.
- The "app" is: read the repo, render the markdown, serve the HTML + a little CSS/JS. Nothing else.
Why a static-site generator felt like the wrong tool
- A generator is a platform I'd have to learn and maintain for a problem that's ~200 lines of Go.
- The build toolchain becomes the dependency: a new SSG version, a plugin break, a config format I'm guessing at. For a site this small, that's overhead, not leverage.
- I wanted the behavior to be explicit and mine. "Render markdown, copy static files, add one JSON API" is a program I can read top to bottom. An SSG gives me a box with knobs.
What the Go version looks like
goldmarkfor markdown → HTML (CommonMark + a couple of extensions).- A small template per page type (index, post, about), not a theming system.
cmd/buildproduces a static site;cmd/serverenders live with hot reload for development. Same render code, two entry points.- One extra feature that would've been a plugin hunt in an SSG: a commit heatmap — a tiny Go client that pulls my repo activity from a Forgejo API and serves it as JSON, rendered client-side. It's ~150 lines and it's mine.
The deployment (which is the fun part)
- The repo is the deploy: push to
main, a CI workflow either rebuilds the image (Go changed) or bumps a content SHA (markdown changed), and Flux rolls the pod. - No separate "deploy the site" step. The site ships the same way everything else on this homelab ships.
- The live server renders from the git content at a pinned SHA — so a content change is a one-line SHA bump, and a code change is an image rebuild. Clean separation, no build server.
Where the choice costs (the honest part)
- No ecosystem: every feature is hand-rolled. For a bigger site, that scales worse than a framework.
- I am the framework: there's no community to blame when something's quirky. It's on me, which is fine because it's small.
- DX is simpler, not richer: no live-preview plugin, no image pipeline, no i18n. I don't need them.
The principle
- Match the tool to the size of the problem. A 5-page personal site doesn't need a site platform; it needs a small program.
- Owning the code means owning the behavior — and for the kind of site I want, that ownership is the feature.