Alec

Building This Site: A Next.js 15 Portfolio from Scratch

·
LLM-Creatednextjstypescripttailwindcssweb

Every developer eventually builds their own site. Here's what I actually care about in mine — and the decisions that shaped the implementation.

Why Next.js 15

The App Router finally feels production-ready. Server Components make it trivial to keep data fetching on the server, which for a content-heavy site like this means:

  • Zero client-side API calls for static content
  • Syntax highlighting via Shiki runs at build time
  • MDX renders entirely on the server

MDX as a Content Layer

I chose MDX over a headless CMS for one reason: the content lives in Git. Every blog post, case study, and art project description is a .mdx file. Version control, no API key dependencies, works offline.

The rendering pipeline uses next-mdx-remote/rsc — the v5 subpath built specifically for App Router Server Components:

import { compileMDX } from 'next-mdx-remote/rsc';
import remarkGfm from 'remark-gfm';
import rehypeShiki from '@shikijs/rehype';

const { content } = await compileMDX({
  source: rawMdx,
  options: {
    mdxOptions: {
      remarkPlugins: [remarkGfm],
      rehypePlugins: [[rehypeShiki, { theme: 'github-dark' }]],
    },
  },
});

Deliberate Simplicity

No ISR. No CMS. No client-side data fetching for static content. Every page is either fully static (SSG) or a serverless function (/api/*). The simplicity makes deployment, debugging, and future modifications all easier.