How this blog is built
1 min read
- nextjs
- markdown
- meta
This site is a small Next.js app. Posts are plain Markdown files, and every page is prerendered at build time.
The moving parts
| Piece | What it does |
|---|---|
content/posts/*.md |
One file per post, with YAML frontmatter |
gray-matter |
Splits frontmatter from the Markdown body |
remark + rehype |
Parse Markdown (with GitHub Flavored Markdown) and turn it into HTML |
shiki |
Syntax highlighting with light and dark themes |
@tailwindcss/typography |
Readable defaults for the rendered article |
Writing a post
Create a new file in content/posts/ named after the URL slug you want, for example my-first-post.md:
---
title: "My first post"
date: 2026-10-01
description: "One sentence that shows up in lists and search results."
tags: [react]
publish: true
---
Write your post here.
A post only goes public once its frontmatter has publish: true. Leave it out, or set it to false, to keep a post private while you work on it. Unpublished posts still show up locally under next dev, marked with an "Unpublished" badge.
The blog index shows six posts per page. Older posts move to /blog/page/2, /blog/page/3 and so on, and every page is prerendered.
Rendering pipeline
The whole pipeline is one unified processor:
const processor = unified()
.use(remarkParse)
.use(remarkGfm)
.use(remarkRehype)
.use(rehypeSlug)
.use(rehypeShiki, {
themes: { light: "github-light", dark: "github-dark" },
defaultColor: false,
})
.use(rehypeStringify);
Each post page calls generateStaticParams, so every post becomes a static HTML file. There is no database and no runtime Markdown parsing.
Keep content as data and let the framework do the rest.
That is the whole idea.