DEV Community

Ratnesh Maurya
Ratnesh Maurya

Posted on • Originally published at blog.ratnesh-maurya.com on

Building This Blog: A Modern Next.js Blog with Markdown

Building This Blog: A Modern Next.js Blog with Markdown

Building This Blog: an MDX‑powered Next.js blog

This blog is a small, opinionated setup for writing long‑form content that feels good to read and fun to build on.

Under the hood it uses static generation, MDX, and a theme‑aware UI that works in both light and dark modes.

Everything after the frontmatter is pure MDX. Components like Callout, Steps, architecture diagrams, flows, and charts are all React components rendered directly in the post body.

Stack I ended up with

I wanted something fast, simple, and easy to reason about over years—not weeks.

The site is a static App Router app. Routes like `/blog/[slug]`, `/til/[slug]`, `/technical-terms/[slug]` are statically generated at build time.

TypeScript keeps the content layer and components honest. Tailwind + CSS variables handle layout and theming.

All long‑form content lives in the repo inside content/, written as `.md` or `.mdx` files with frontmatter.

Views, upvotes, and UTM events are stored in Supabase and surfaced through a custom analytics dashboard.

Enter fullscreen mode Exit fullscreen mode

How content works

All posts are simple files in the repo—no CMS required.

---
title: "Your Post Title"
description: "Post description"
date: "2024-01-20"
author: "Your Name"
tags: ["tag1", "tag2"]
category: "Category"
featured: true
---

Your content here...

Enter fullscreen mode Exit fullscreen mode
  • Markdown (.md) posts go through a Remark pipeline and are rendered as HTML.
  • MDX (.mdx) posts are compiled at runtime in the page using next-mdx-remote/rsc, with a shared component map.

For posts that need diagrams, flows, or charts, I use .mdx and drop in components like ArchitectureCard, FlowStep, and DemoBarChart.

Authoring flow

Add a new `.md` or `.mdx` file to content/blog/ with frontmatter for SEO, tags, and images.

Run npm run dev and iterate on copy, diagrams, and layout until the post feels polished.

Push to the main branch. The build step generates static HTML for every route and updates search data + OG images.

Enter fullscreen mode Exit fullscreen mode

Architecture of the blog

At a high level, the blog is just three pieces: browser, Next.js, and Supabase.

Readers get fully rendered HTML from the CDN, with minimal JavaScript on top for upvotes, analytics, and small interactions.

Next.js statically generates pages for blog posts, TIL entries, technical terms, and lists. It also exposes a few API routes for analytics.

Supabase stores per‑page views, upvotes, and UTM events that feed the analytics dashboard and charts.

Enter fullscreen mode Exit fullscreen mode

Request–response flow for a page view

Here’s how a single blog page view flows through the system.

The CDN serves a pre‑rendered HTML page that was generated at build time.

Next.js hydrates the page; components like the upvote button, custom cursor, and view counter start working.

A lightweight request records the view / upvote in Supabase without blocking the reader.

Aggregated stats are used to power Recharts visualizations on the analytics page.

Enter fullscreen mode Exit fullscreen mode

Visualizing traffic with charts

The same Recharts setup used in the analytics dashboard is available inside MDX posts.

Charts are plain React components exposed to MDX. They respect the global theme and use the same accent palette as the rest of the site.

Performance before and after

Static export plus small tweaks around assets made a noticeable difference in user‑facing numbers.

Why this setup works for me

  1. Files as the source of truth – I can write posts in a text editor, version them in git, and refactor them like any other code.
  2. Static by default – Most pages are static HTML, which is great for speed and reliability.
  3. MDX when I need power – Architecture diagrams, flows, and charts are just components; I only reach for them when a post really needs them.
  4. Theme‑aware UI – Components use the same CSS variables as the rest of the app, so they look good in both light and dark modes.

If you want to explore the implementation details, the full source code is on GitHub. You could clone it, point it at your own content folder, and have a similar blog running in minutes.

Top comments (0)