← Tech

Hello World: Building My Digital Garden with Next.js 15

nextjsreacttailwindmdx

How and why I built this site: the tech stack, the decisions, and what I learned along the way.

Every developer eventually builds their own website. Most never finish it. This is my attempt at actually shipping something.

Why Next.js 15?

I come from a C# / .NET background. Server-side rendering, strong typing, a clear separation between data access and presentation. These things feel natural to me. Next.js 15's App Router brings that same thinking to the frontend.

React Server Components let you write components that run only on the server: they can read from the filesystem, query a database, even make fetch calls directly. No useEffect, no loading states, no client-side data fetching for content that doesn't change per user. It's conceptually similar to a Razor page or a controller action in ASP.NET MVC.

// This runs on the server at build time (SSG) or request time (SSR).
// The `fs` module is fine here. The browser never sees this code.
import fs from "fs";
 
export async function getPost(slug: string) {
  const raw = fs.readFileSync(`content/tech/${slug}.mdx`, "utf-8");
  return raw;
}

The MDX pipeline

MDX lets you write Markdown with JSX inside it. The pipeline goes:

  1. gray-matter splits the YAML frontmatter from the content body
  2. remark-gfm adds GitHub Flavoured Markdown (tables, strikethrough, task lists)
  3. rehype-pretty-code wraps code blocks with Shiki syntax tokens
  4. compileMDX from next-mdx-remote/rsc turns it all into React JSX

The result is a clean <article> element styled by Tailwind's prose utility.

Dark mode without JavaScript

One thing I'm proud of: the syntax highlighting works in both light and dark mode with zero client-side JavaScript. rehype-pretty-code writes both colour sets into the HTML. The CSS color-scheme property on <html> controls which one is visible.

:root { color-scheme: light; }
.dark { color-scheme: dark; }

next-themes toggles the dark class. The browser CSS does the rest.

What's next

  • Add Supabase for persistent data (comments? newsletter?)
  • Implement reading time estimates
  • Add an RSS feed
  • Improve mobile navigation

More posts incoming. The hard part is done: the infrastructure exists. Now I just have to write.