SR
0%5 min left
All posts
5 min read

Why I built my own blog instead of using Substack

Substack would have taken twenty minutes. This took two weekends. Here's the honest math on why I picked the slower option and the cases where you absolutely shouldn't.

I could have set up a Substack in twenty minutes. A Hashnode in ten. A Medium account in three. Instead I spent two weekends building a blog on top of my portfolio with Next.js, Supabase, a Tiptap editor, and a custom publishing workflow that nobody but me will ever use.

This is the part where most "why I built my own blog" posts pivot to something high-minded about ownership and the open web. I'll get there. But the honest reason is smaller and more selfish:

I wanted to know if I could.

That's a fine reason. I just don't want to pretend it isn't the main one.


The Platform Tax Nobody Mentions#

Hosted platforms are great until you want to do something they didn't anticipate.

Then you find out you've been paying a tax the whole time and didn't notice.

A few taxes I wasn't willing to keep paying:

  • The URL tax. My posts living at someplatform.com/@shivang/... instead of shivangramola.com/blog/.... Every link I share is doing SEO work for someone else's domain.
  • The design tax. Every hosted platform has a "voice" baked into its CSS. You can't fully escape it. My portfolio has a specific feel — type, motion, color — and a Substack embed in the middle of it would look like a tenant.
  • The data tax. I want my posts as rows in a Postgres table I control, not as JSON behind someone's API that may or may not exist in five years. I've migrated a blog off WordPress before. I know how that ends.
  • The AI tax. I added an llms.txt file the day I shipped this. I want LLMs to crawl my writing on my terms, not the platform's.

None of these were dealbreakers individually.

Together they made the choice obvious.


What "Owning It" Actually Buys#

The phrase gets thrown around like a slogan.

Here's what it concretely means for me, in features I now have because nobody can take them away:

  • The URL structure is mine. Slugs, redirects, canonical tags, sitemap — all of it lives in my repo.
  • The editor is mine. Tiptap with the exact toolbar I want. Markdown paste support because I draft in Obsidian. Image uploads that go straight into a Supabase storage bucket I own.
  • The reading experience is mine. Tag filters, year filters, pagination, a "Latest Writing" section on the home page that updates automatically when I publish. None of that was a setting toggle. All of it was a UI decision.
  • The data model is mine. A posts table. A status column. RLS policies that say anonymous users can only see published posts; I can see everything. Done.
  • The publishing flow is mine. Push to main, Vercel rebuilds, the sitemap updates, the post is live. No "publish" button hiding three confirmation modals.

That's the part of "ownership" that's real.

Not the abstract freedom — the very specific list of small annoyances I no longer have.


The Stack, Briefly#

Because someone always asks:

  • Next.js (App Router) for the frontend and the SSR/metadata story.
  • Supabase Postgres for the posts table. Row-level security so the public can read published posts and only authenticated sessions can write anything.
  • Supabase Storage for cover images and inline uploads, with a public bucket and an authenticated-write policy.
  • Tiptap as the editor, with StarterKit, Link, Image, Placeholder, and a custom Markdown-paste handler so I can paste from my notes app and not lose formatting.
  • sanitize-html for sanitizing the stored HTML on the server. (I started with isomorphic-dompurify and switched after Vercel's runtime didn't love it.)

Total moving parts: small enough that I can read every line of the blog code in one sitting.

That's the bar I wanted to hit.


The Honest Cost#

I want to be fair about what this approach actually costs, because most posts in this genre are quietly dishonest about it.

  • Two weekends to ship the first version. Then a third weekend tightening SEO — structured data, sitemap, robots, OG images, the icon.
  • An ongoing ~5% mental tax. When I want to add a feature (say, RSS, scheduled publishing, or comments), I have to actually build it. Substack ships those for free.
  • No built-in audience. Substack's network effect is real. My blog at launch has zero subscribers. I'm relying on slow compounding from search and direct shares.

If any of those costs feels prohibitive right now, don't build your own.

Use the hosted thing.

Write the posts.

Migrate later when the costs flip.


Who Should Build Their Own#

Three honest heuristics:

  • You're a developer and you'd genuinely enjoy the build. Not "I should enjoy it" — actually enjoy it. If the build feels like homework, you'll abandon it half-finished and have neither a blog nor a portfolio piece.
  • Your blog is going to live next to other things you've built. A portfolio. A product. A documentation site. The integration is the value.
  • You publish slowly enough that platform features don't matter much. I write in bursts. I don't need a paid-newsletter funnel. If I were trying to build a 50,000-subscriber publication, Substack's tooling would be worth more than my custom setup.

If you don't hit at least two of those, use the hosted option and spend your weekends writing instead of yak-shaving.


What This Post Is, Really#

It's the first post on a thing I built.

So it gets to be about the thing.

The next ones will be about work — shipping AI features that are allowed to say "I don't know," migrating twenty AI tools to Next.js 15 without breaking SEO, putting five thousand vehicles on a Mapbox at 60fps.

The fun stuff.

This was the warm-up.