file-based-blog-with-nextjs.md
File-Based Blogs on Next.js Static Export
How to ship a markdown blog with zero database, full SEO, and static export the same stack powering mahdi.is-a.dev.
- Next.js
- Markdown
- Static Export
Markdown files in a content/ folder are underrated. No CMS login, no API keys, no migration scripts just git history and a build step.
Why file-based?
For a personal tech blog, the requirements are simple:
- Version control every edit is a commit
- Fast builds parse at build time, serve static HTML
- Portability move hosts without exporting a database
- Developer UX write in VS Code, preview locally
Static export (output: 'export') on Next.js 13+ makes this especially clean. Server components read the filesystem during next build, generate HTML for every route, and you deploy plain files to any CDN.
The pipeline
A typical setup looks like this:
// lib/blog.ts simplified
import fs from "fs";
import matter from "gray-matter";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import rehypePrettyCode from "rehype-pretty-code";
import rehypeStringify from "rehype-stringify";
export async function getPostBySlug(slug: string) {
const raw = fs.readFileSync(`content/blog/${slug}.md`, "utf8");
const { data, content } = matter(raw);
const html = await unified()
.use(remarkParse)
.use(remarkGfm)
.use(remarkRehype)
.use(rehypePrettyCode, { theme: "one-dark-pro" })
.use(rehypeStringify)
.process(content);
return { ...data, html: String(html) };
}Frontmatter holds metadata; the body stays pure markdown.
Supported markdown features
- GFM tables,
strikethrough, andinline code - Task lists with checkboxes
- GitHub alerts, footnotes1, and autolinks like https://nextjs.org
- Syntax highlighting with line numbers, filenames, and
{line}highlights
- Parse markdown at build time
- Highlight code with Shiki themes
- Client-side CMS (not needed yet)
[!TIP] Use
published: falsein frontmatter to keep drafts out of production builds.
[!WARNING] Static export means no runtime API routes pre-generate RSS and sitemaps during
next build.
SEO without a server
Even without SSR at request time, you can ship:
- Per-page metadata via
generateMetadata sitemap.tsfor crawlers- RSS feed generated at build time into
public/feed.xml - JSON-LD Article schema on each post
The trick with static export is that dynamic route handlers don't run in production pre-generate feeds and sitemaps during the build instead.
Frontmatter schema
Keep it minimal but expressive:
---
title: "Your post title"
description: "One sentence for OG tags and RSS"
date: "2025-05-12"
updated: "2025-05-14" # optional
tags: ["React", "Next.js"]
featured: true
published: true
---Set published: false to hide drafts from production builds without deleting files.
Takeaways
File-based blogs scale down beautifully. You won't outgrow them until you need multi-author workflows, scheduled publishing, or a non-technical editor and by then you'll know exactly what CMS features you actually need.
Until then: write markdown, commit, deploy.
Footnotes
-
Footnotes render at the bottom of the post great for citations without breaking reading flow. โฉ
Related
Continue reading
More notes on similar topics.
A living reference for writing posts thumbnails, code, tables, alerts, footnotes, images, audio, video, and YouTube embeds.
- Markdown
- Blog
The horse is doing the running. You're still the one who has to stay balanced, read the terrain, and not fall off. That's the whole difference between vibe coding and actually directing the thing.
- AI Engineering
- Vibe Coding
The Day the Facility Guy Shipped a Feature to My App
July 29, 2026
I taught our building's maintenance guy how to vibe code for fun. Twenty minutes later he'd chatted his way into a working feature inside one of my real apps. Here's what actually happened, and why it didn't disprove anything I've written in this series.
- AI Engineering
- Vibe Coding