xx.lanka
← All posts

How this site is built

1 min read
engineeringnextjs

Every post here is a plain markdown file in the repo. No CMS, no database, no login screen standing between me and writing. This post is also the documentation.

Adding a post

Drop a .md file into content/posts/. The filename becomes the URL:

content/posts/my-new-post.md   →   lanka.lol/writing/my-new-post

The frontmatter carries everything the site needs:

---
title: "My new post"
description: "One or two sentences for lists, RSS, and social cards."
date: "2026-08-26"
tags: ["ai", "engineering"]
draft: false
---

draft: true keeps a post out of every list and feed; it only renders when opened directly in development.

The pipeline

At build time each file goes through gray-matter for frontmatter, then a unified/remark/rehype chain: GFM tables and task lists, heading slugs, anchored headings, and Shiki for syntax highlighting — compiled to static HTML with both light and dark themes baked in as CSS variables. No client-side highlighter, no layout shift, no flash.

Code blocks look like this:

export function readingMinutes(content: string): number {
  const words = content.trim().split(/\s+/).length;
  return Math.max(1, Math.round(words / 220));
}

The rest

  • Next.js App Router — every page statically prerendered; dynamic routes come from generateStaticParams.
  • Tailwind CSS v4 with the typography plugin for long-form reading.
  • RSS at /rss.xml, plus sitemap.xml and robots.txt generated by the framework.
  • OG images rendered per post at build time from the title, so links shared anywhere get real cards.

The whole thing is fast because there's almost nothing to it: HTML and CSS, shipped. That was the design constraint, not an accident.