All posts
Development javascriptmarkdown

Building a blog one last time.

N

Nadim

March 7, 2026

·

3 min read

Table of contents

Felt like a good pilot post — talking about how this site is actually built.

Have I built blog sites before? Many times. I've npx'd my way into more blog setups than I can count, that's not that different from what AI does now. Almost every JS static site generator — Astro, Gatsby, Next.js — ships with a blog starter that handles all the wiring: Markdown rendering, frontmatter for post metadata, RSS, the works. I could have gone with Hugo too, since I've been writing mostly Go for the past couple of years, but Hugo comes with a lot of Hugo-specific concepts to learn, and more importantly — adding a database or an interactive demos section gets complicated fast when your entire site is statically generated. There's no backend to talk to.

And thinking about it, even the JS framework approach carries risk. Gatsby is effectively dead — most people have moved to Astro, which was recently acquired by Cloudflare. That acquisition is actually good news for long-term maintainability, but it's also a reminder that frameworks come and go, and you're betting your project on someone else's roadmap.

But to avoid all that, and since we have AI, I opted for a more low-level approach of just building my own server-side blog with a couple of Go packages, mainly goldmark.


The browser editor rabbit hole

Since I can prompt my way through most implementation problems now, I thought: why not build a proper in-browser editor? Import Tiptap or Quill, store everything in the database as rich text or JSON, and write directly in the app. No local files, no deploys for content. Everything queryable. Full-text search, vector search, drafts, scheduled publishing — a database makes all of that easy. It's the right foundation for a lot of things I'd want to do later.

So I worked on that for a while. Got a decent editor running. Tried a few different approaches for storing and rendering the content.

And then I sat down to actually write something and immediately missed Markdown.

Not the syntax specifically — I missed the feel of it. Writing in VSCode, in a plain file, with no toolbar and no formatting buttons. The editor in the browser kept pulling my attention toward the wrong things.


The solution I landed on

What I ended up with is a middle path that I'm genuinely happy with.

I write .md files locally in content/posts/. When a new file appears there, it creates a pending blog post — something that exists on disk but hasn't been registered in the database yet. There's a step to "publish" it, which writes the post to Postgres with the metadata, makes it queryable, and makes it live on the site.

So I get both things:

  • Writing in VSCode, in Markdown, the way I actually want to write
  • A database as the source of truth for everything the app needs to query or serve

The .md file is where I write. Postgres is where the app reads. Different tools, different jobs, no overlap.


Would I have found this without AI?

Probably, eventually. But I would have spent a lot less time on the WYSIWYG editor first. Having AI available made me more willing to go down the complicated path — because the implementation cost felt low. Spinning up a Tiptap integration used to be a half-day of reading docs and wiring things together. Now it's an hour. So I did it, learned I just don't like writing in a browser editor, and moved on.

The more I build with AI the more I think its biggest advantage is exactly that — it lowers the cost of finding out something doesn't work. You try more things. Some of them fail faster. You end up somewhere better than where you started. If I'd just opened Replit or Claude Code and typed

"Build me a blog where I can write and publish posts from a dashboard in the browser, with a rich text editor, drafts, and scheduled publishing"

I'd probably have ended up with a React app that looked better than what I have now, had more features, and that I would have quietly hated every time I opened the codebase. Instead I kept my hypermedia Go backend, some template files, and a database. No fancy static site generation. I'm even thinking about adding cache invalidation when posts are edited, something like what Vercel does with incremental static regeneration, mostly just to learn how it works.

The blog is simple. The solution is obvious in hindsight. It took trying the complicated version first to know that.