Why I Chose Go for My Blog (And Not Next.js)
The Obvious Choice I Didn't Make
I've been building with Next.js professionally. My recruitment platform Elite runs on it. I know the ecosystem inside and out — server components, middleware, API routes, the works.
So when I decided to build a personal blog, Next.js was the obvious choice. I didn't pick it.
The Problem With Obvious
Next.js is a phenomenal framework for interactive web applications. But a blog isn't an interactive web application. A blog is a read-heavy, content-driven site where the primary interaction is scrolling and clicking links.
For that use case, Next.js brings:
- A Node.js runtime (memory-hungry, GC pauses)
- A build step that takes 30+ seconds
- Client-side JavaScript bundles for... reading text
- A
node_modulesfolder larger than the content it serves
Meanwhile, Go brings:
- A single static binary (15MB, zero dependencies)
- Sub-millisecond template rendering
- Negligible memory footprint (~10MB RSS)
- Compile times under 2 seconds
Gin: Express.js Energy, Go Performance
The Gin framework is what sold me. Coming from Express.js patterns, Gin feels immediately familiar:
router.GET("/article/:slug", handler.ArticleDetail)
router.GET("/api/v1/articles", handler.APIArticles)
Middleware chains, route groups, parameter extraction — it's all there, just faster. Gin's zero-allocation router means the framework adds almost no overhead to each request.
What I Actually Needed
My blog requirements are simple:
- Read markdown files from a directory
- Parse frontmatter metadata
- Render HTML with templates
- Serve static CSS
- Optionally expose a JSON API
That's it. No authentication, no database, no real-time features. Go handles all of this with the standard library plus two dependencies (Gin and Goldmark for markdown).
The Architecture
blog/
├── main.go # Entry point
├── internal/
│ ├── config/ # Environment config
│ ├── handler/ # HTTP handlers + router
│ ├── model/ # Article struct
│ ├── service/ # Article loading + markdown parsing
│ └── middleware/ # Security headers
├── templates/ # Go HTML templates
├── static/css/ # Stylesheet
└── content/articles/ # Markdown files
Clean separation. Each package has one job. No circular dependencies. This is the Go way — boring, predictable, maintainable.
The Tradeoffs
I won't pretend this is all upside. Things I miss from Next.js:
- Hot reload — I have to restart the server when templates change (Air fixes this, but it's extra tooling)
- Component model — Go templates are functional but primitive compared to React components
- Ecosystem — Need auth? Payments? In Next.js, there's a library. In Go, you're often writing more yourself.
But for a blog? These tradeoffs are worth it. The result is a site that loads instantly, costs nothing to host, and will outlive whatever JavaScript framework is trending next year.
The Lesson
Pick the tool that matches the problem, not the tool you know best. Sometimes the right choice is the one that does less.