Portrait of Shubham LatakeShubham LatakeFull Stack Engineer
← Back to Blog

Why I Rebuilt My Site Around Plain Text Files

Published · 2 min read

  • #nextjs
  • #mdx
  • #typescript

I've restarted this site more than once. Every previous attempt died the same way: I'd pick a CMS, spend an evening wiring it up, and then never write anything, because publishing meant logging into a dashboard.

So this version has no dashboard. A post is a file.

How it works

Every post is an .mdx file in content/blog/. Writing means adding a file and committing it. The frontmatter is validated with zod when the file is read, which means a typo fails the build instead of quietly shipping a page with a missing date.

const frontmatterSchema = z.object({
  title: z.string().min(1),
  excerpt: z.string().min(1),
  date: z.coerce.date(),
  category: z.string().min(1),
  tags: z.array(z.string()).default([]),
  draft: z.boolean().default(false),
});

That schema is the whole content model. Reading time is derived from the body rather than typed by hand, and the table of contents above is built by walking the markdown for ## headings — using the same slugger the renderer uses, so the anchors always line up.

What I deliberately left out

Categories are captured on every post from day one, but there are no category pages and no tag filtering yet. Both are a routing change whenever I want them, and neither needs the existing posts to be touched. Building navigation for six posts would have been building for an audience that doesn't exist.

The same logic applies to search, comments and pagination. They're easy to add later and impossible to justify now.

The part that actually matters

All the filesystem work lives in one module. Pages and components only ever receive typed objects, so if this ever does outgrow flat files, swapping in a real CMS means rewriting a single file.

That constraint is doing the real work here. Not the file format — the fact that nothing else in the codebase knows or cares where posts come from.

Share:XLinkedIn