Today my blog broke.
Not in a dramatic way. No deploy failed. No DNS record was wrong. No server was out of memory. The site was just showing an error, and at first it looked like one of those small production problems that should take five minutes to understand.
It was not the code I had just changed.
The site was reading my Hashnode publication through their GraphQL API. That had been working fine. The homepage fetched the posts, rendered the cards, and each article page pulled the post content from Hashnode. Simple enough.
Then the API stopped returning API responses.
Instead of JSON, the GraphQL endpoint started returning an HTML page about GraphQL API access moving to a paid offering. Next.js tried to parse that response as JSON during server rendering, the page crashed, and Vercel correctly served a 500.
The frustrating part is not that a company changed a plan. That happens. The frustrating part is when something that behaved like public infrastructure suddenly stops behaving that way, and the first signal you get is your own production site breaking.
What I tried first
I did not want to turn this into a migration project.
I just wanted the blog back.
The first fix was defensive: stop the site from crashing when Hashnode returns something unexpected. That got the homepage responding again, but it also meant the posts were gone because the source of truth was no longer readable through the path I was using.
Then I tried the obvious recovery routes.
I checked the old custom-domain URLs. They now pointed to my own Vercel app, so they could not help.
I checked sitemap and RSS endpoints. Nothing useful came back from the new setup.
I checked the public Hashnode profile. That still exposed some metadata: titles, slugs, dates, excerpts, read times. Enough to reconstruct the post list, but not enough to fully restore the articles.
I checked the Hashnode discussion pages. Same story. They had the title and excerpt, but not the full article body.
I also tried the Hashnode subdomain directly, but that route was either blocked or no longer serving the original article pages in a way I could use.
At that point the decision became pretty clear: I could keep fighting the platform, or I could remove the runtime dependency.
The decision
For now, I moved everything to MDX files in the repo.
It is not fancy. It is not a CMS. It does not have the smooth editor experience Hashnode had. But it has one major advantage: the blog now builds from files I control.
The homepage reads frontmatter from content/posts/*.mdx.
The post pages render MDX locally.
The old root-level slugs redirect to the new /posts/... paths so existing links still work.
There is no GraphQL request during page render anymore. No external blog provider has to be available for my homepage to load.
That is boring, and boring is exactly what I want from a personal blog right now.
The tradeoff
The downside is obvious: I do not have the full old article bodies restored yet.
Hashnode exposed enough public metadata to rebuild the structure, but not the full content. So the current MDX files are temporary local archives with recovered excerpts and placeholder bodies. They keep the site alive, preserve the slugs, and give me somewhere clean to paste the full content when I can export it properly.
This is not the final blogging setup.
It is a bridge.
Why I am not over-optimizing this
I am fully focused on indie app development right now.
That changes the decision-making.
If this were my main product, I would spend more time designing the publishing workflow, building preview tooling, adding richer MDX components, improving content backups, and maybe evaluating a new CMS.
But this blog is supposed to support the work, not become the work.
So I chose the smallest reliable system I could own:
- Markdown-like files in the repo
- Static generation
- No external content API at request time
- Easy migration path later
It emulates most of what I needed from the editor for now: title, excerpt, tags, date, reading time, and the article body. It is not as comfortable, but it is predictable.
And predictability matters a lot when your time is limited.
The lesson
A hosted writing platform is convenient until it becomes part of your production runtime.
If a blog is rendered from an external API on every request, that API is no longer just a publishing tool. It is infrastructure. It can break your site. It can change pricing. It can change access rules. It can return HTML where your code expects JSON.
That does not mean every personal blog needs a custom CMS or a complicated publishing pipeline.
It just means the source of truth deserves some thought.
For me, at least for now, the source of truth is going back into Git.
I will probably revisit the setup when I have more room to think about blogging again. Maybe I will use another provider. Maybe I will improve the MDX workflow. Maybe I will build something small for myself.
But today the goal was simpler: get the blog out of the broken path, recover what I could, and move on.
That is done.