Building a Zero-Maintenance Blog with MDX and Next.js 15
How to build a git-powered blog using MDX, gray-matter, and Next.js App Router — no database required.

This is a technical article for developers. If you run a salon, restaurant or trade business, start here instead: what a website really costs and what your website actually needs.
Many small websites over-engineer their blog. You set up a CMS, configure webhooks, provision a database, and spend more time on infrastructure than writing. MDX with Next.js App Router eliminates all of that — your content lives in the repository, versioned alongside your code, with zero runtime dependencies.
Why MDX Over a Headless CMS
A headless CMS like Sanity or Contentful is the right choice when a non-technical team needs to publish content. For a developer's personal blog, it introduces unnecessary coupling:
- Cold-start latency — every page render hits an external API
- Availability dependency — your CMS going down takes your blog with it
- Context switching — writing in a browser editor instead of your IDE
MDX flips this. Content is a .mdx file. Deployment is a git push. There is no CMS to maintain.
Project Structure
content/
blog/
nextjs-15-architecture.mdx
trading-bot-design.mdx
lib/
mdx.ts ← parse frontmatter + content
app/[locale]/blog/
page.tsx ← listing
[slug]/page.tsx ← detail
Parsing MDX Files with gray-matter
The core of the system is a single utility that reads .mdx files from disk and maps them to your data model:
ts
gray-matter splits the YAML frontmatter from the body. The rest is plain TypeScript — no special MDX runtime needed at this stage.
Rendering MDX in the App Router
For the detail page, Next.js recommends @next/mdx or the lighter next-mdx-remote. Because we're loading files at request time (not statically importing), next-mdx-remote fits better:
ts
MDXRemote from the /rsc export is a React Server Component — it compiles and renders MDX on the server with zero client JavaScript.
Frontmatter Schema
A consistent frontmatter structure prevents edge cases in the listing page:
yaml
Keep published: false on drafts — the getMdxPosts filter excludes them without touching routing.
Static Generation with generateStaticParams
For maximum performance, pre-render all posts at build time:
ts
Combined with next/image for cover images and a CDN in front of Vercel, Time to First Byte drops to single-digit milliseconds.
Adding Custom MDX Components
One of MDX's biggest advantages is embedding React components in prose. Map component names to implementations in one place:
ts
Now any .mdx file can use <Callout> or <CodeBlock> inline.
Trade-offs
What you gain:
- No database, no CMS API, no webhooks
- Content versioned in git — drafts are branches, reviews are PRs
- Full IDE tooling: autocomplete, spell-check, refactoring
What you give up:
- No visual editor for non-technical collaborators
- No built-in media management (use Cloudinary or
public/) - Redeployment required to publish (acceptable for solo-maintained sites)
Conclusion
For a site maintained by a single developer, an MDX-based blog is the right level of complexity. The setup fits in two files, scales to hundreds of posts without a database, and keeps the authoring experience inside the tools you already use. The only maintenance cost is an occasional npm update for gray-matter and next-mdx-remote.
Working on something similar?
I build fast marketing sites and booking systems for small businesses across Europe — freelance, remote. I reply within 24 hours.
Get in touchRelated articles
A Website for Trade Businesses: Inquiries Instead of Missed Calls
Why electricians, plumbers and other trades lose jobs on the phone — and how a website with an inquiry form, photo upload and emergency contact turns missed calls into structured inquiries. With a clickable demo.
Read articleBooksy, Fresha & Co. vs. Your Own Booking Website: An Honest Comparison
What booking marketplaces really do for salons, what they cost over time — and when your own website with online booking makes sense. A fair comparison, not an either-or.
Read article