engineeringnextjs

Building the Blog: MDX, Callouts, and Code Highlighting

2026-07-03

When I added a blog to this portfolio, I didn't just want plain Markdown — I wanted the same kind of rich content you see on engineering blogs: callout boxes, syntax-highlighted code, and properly optimized images.

tip

This entire post is rendered through the same MDX pipeline described below — it's real content, not a test fixture.

Rendering pipeline

Posts live in content/blog/*.mdx as frontmatter + Markdown/MDX body. lib/mdx.ts reads them with gray-matter, and app/blog/[slug]/page.tsx renders the body with next-mdx-remote/rsc's <MDXRemote>:

<MDXRemote
  source={post.content}
  components={mdxComponents}
  options={{ mdxOptions: { rehypePlugins: [rehypeHighlight] } }}
/>

rehype-highlight adds hljs-prefixed classes to every fenced code block at build time, so syntax highlighting works with zero client-side JavaScript.

warning

Because posts are statically generated via generateStaticParams, adding a new post requires a rebuild — there's no live database behind this.

Custom components

Two custom components are registered in components/mdx/mdxComponents.tsx: a <Callout> component (used throughout this post) and an img override that swaps plain <img> tags for next/image, so Markdown images stay responsive and lazy-loaded automatically:

A photo from my profile

The result is a Markdown authoring experience with production-grade output — no manual image sizing, no unstyled code blocks, and reusable callouts for asides.