Why I rebuilt this site in MDX

Douglas Pereira

I wanted a site I would actually write in. Not a CMS, not a component forest. A page is a folder with a page.mdx. If the sentence is wrong, I change the sentence and ship.

File-system routing is the CMS

Next.js App Router already maps folders to URLs. MDX on top of that means the content is the route. No slug table, no preview iframe, no "publish" button that can drift from git.

The compiler is @next/mdx with the Rust MDX pipeline (experimental.mdxRs). That buys GFM and speed. It also means no rehype/remark plugins unless I drop back to the JS compiler. I accepted that constraint on purpose: syntax highlighting comes from sugar-high in mdx-components.tsx, not from a plugin stack.

const nextConfig = {
  pageExtensions: ['mdx', 'ts', 'tsx'],
  experimental: { mdxRs: { mdxType: 'gfm' } }
}

English and Portuguese are sibling trees (app/en/..., app/pt/...). Duplication is honest: a translation is a second piece of writing, not a key in a JSON blob that nobody proofreads.

What I refused

  • Contentlayer / Velite — extra schema for ten posts is a build I do not want to debug at 11pm.
  • MDX remote from a database — the point of this site is that git is the source of truth. RSC can load MDX from disk; it does not need a round trip.
  • A custom blog enginenext-mdx-blog already had the boring parts: metadata, sitemap, useMDXComponents.

The design is a ~42rem column, Poppins, prefers-color-scheme. The site should get out of the way so the words and the snippets can do the work.

References