qann_thoughts/hardcoded-blog.mdx
published
5 min read
// field_notes — infrastructure

our blog has no database. here's why that's the right call.

We built the Qann thoughts section with MDX files and no CMS. No Postgres, no admin panel, no content API. A decision that looks like laziness but is actually a position on where complexity earns its place.

6 April 2026Qann Commerce

The thoughts section on qann.co has no database.

No CMS. No admin panel. No content API. No Postgres instance sitting somewhere charging us money while we sleep. To publish a post, someone creates a text file, writes in it, and deploys the site. The file existing is the publish action.

When we tell developers this, the reaction is usually something between mild surprise and quiet judgment. When we tell founders, the reaction is usually: "wait, can we do that for our site too?"

This post is about why we made that choice, when it is the right call, and when it is not.

what we actually built

The thoughts section runs on MDX: markdown files with the ability to include React components if needed. Each post is a .mdx file in a folder called content/thoughts/. The file has a small header block with the title, date, excerpt, reading time, and tag. Everything else is the post itself, written in plain text with standard markdown formatting.

At build time, Next.js reads the folder, parses the files, generates the pages. No runtime database queries. No content API calls. The posts are part of the build, not fetched from somewhere else at render time.

The whole system is about 60 lines of code. It has been running without touching it since the day it was built.

the case for not having a database

Most content infrastructure is built to solve a problem that does not exist yet.

A database-backed CMS makes sense when you have multiple authors who cannot be trusted with a code deployment. It makes sense when you are publishing dozens of pieces a week and need an editorial workflow with drafts, approvals, and scheduled publishing. It makes sense when the content is so dynamic that it needs to be updated without a redeploy.

For a company blog that publishes once or twice a month, written by people who are comfortable with text files, none of those problems exist. You would be building infrastructure for a problem you do not have, paying for it every month, and adding a dependency that can break, go down, or change its pricing.

We have a principle at Qann: every tool passes one test. Does this create fewer problems than it solves? A CMS for a low-volume company blog does not pass that test. It adds a login to remember, a service to maintain, a potential point of failure, and a monthly cost. In exchange, it gives you a nicer writing interface. That is not a trade worth making.

what you lose

Nothing is free. The file-based approach has real limitations and it is worth being honest about them.

No non-technical publishing. If the person writing the post cannot drop a file into a folder and run a deployment, this does not work for them. That is a genuine constraint. For Qann right now, everyone who writes for the site is comfortable with this workflow. The day that changes, the system needs to change with it.

No scheduled publishing. You cannot write something today and set it to publish next Tuesday. You deploy it or you do not. This is occasionally inconvenient. We have not found it to be a real problem at our publishing frequency.

No drafts in a shared environment. Drafts live on your local machine or in a branch. There is no "draft" state on the live site. Again, this works fine for a small team. It would not work for a publication with a proper editorial process.

No rich media management. Images need to go into the public folder manually. There is no asset library. This is the most genuinely annoying limitation in practice.

when to use a database

The honest answer is: when the limitations above become real problems, not theoretical ones.

The signal is not "we are growing and might need this someday." The signal is "we are actually experiencing friction because of the current system right now." When a non-technical team member cannot publish without engineering support. When you are publishing frequently enough that the deployment workflow is slowing you down. When you have enough content that managing flat files feels chaotic.

At that point, reach for a CMS. Not before.

The best infrastructure decisions are made in response to real constraints, not imagined future scale. We see this pattern constantly in client work. A five-person team with a Salesforce implementation that requires a dedicated administrator. An e-commerce brand with a microservices architecture built for a traffic volume they have never come close to. Tools chosen for the company they hope to become, not the company they are. The overhead of maintaining these systems is real and it compounds.

Build for where you are. Migrate when you have to.

the broader principle

The file-based blog is a small example of a larger position.

Complexity has a cost. Every layer of infrastructure you add creates a surface area for things to go wrong, a dependency you did not have before, and cognitive load for the people who have to understand and maintain the system. Sometimes that cost is worth paying because the complexity is solving a real problem. Often it is not.

The tech industry has a strong bias toward sophisticated solutions. There is status in the architecture diagram. There is no status in the text file. But the text file that has been running without incident for three years while the architecture diagram became a legacy system is making a different kind of argument.

We are not anti-complexity. We run Odoo ERP across multiple businesses. We build custom software for clients. We integrate AI into real operational workflows. When complexity earns its place, we embrace it.

But a blog is a blog. It publishes words. The words should be the complicated part.


this post was published by creating a text file and running one command. total time from draft to live: four minutes.

— Qann Commerce · qann.co

← all posts