In short
A blog is the classic Next.js project. You'll use dynamic routes, static generation, ISR and metadata together, which is exactly what content sites at real companies do.
A blog built on Next.js with SSG/ISR, dynamic routes for posts, and metadata generation — a very common real-world Next.js use case.

Think of it like this
A diary that updates itself
Imagine a printed diary where new pages appear on their own every few hours, and each page has a neat title on top. Your blog is that: posts are printed in advance, refreshed in the background, each with its own label.
Watch it happen
From .md file to blog page
1/5content/posts holds three files, each with a title and date at the top.
The big ideas
What you need to know
Posts from Markdown or a CMS
Read .md or .mdx files from a folder, or fetch from a headless CMS like Sanity or Contentful.
SSG plus ISR
Prebuild posts with generateStaticParams, and use revalidate if content comes from a CMS.
SEO basics
generateMetadata per post, a sitemap of all posts, and readable slugs.
List and detail
A /blog index with pagination or tags, and /blog/[slug] for each post.
How it works
Build plan
- 1
Content source
Write three Markdown posts with a title, date and slug at the top.
- 2
Blog index
List posts newest first with title, date and a short excerpt.
- 3
Post page
A [slug] route with generateStaticParams and notFound() for bad slugs.
- 4
SEO layer
Add generateMetadata, a sitemap and Open Graph images.
See it in code
Walk through the code
1// lib/posts.ts2import fs from "node:fs/promises";3import path from "node:path";4import matter from "gray-matter";5 6const DIR = path.join(process.cwd(), "content/posts");7 8export async function getAllPosts() {9 const files = await fs.readdir(DIR);10 const posts = await Promise.all(files.map(async (file) => {11 const { data } = matter(await fs.readFile(path.join(DIR, file), "utf8"));12 return { slug: file.replace(/\.mdx?$/, ""), title: data.title, date: data.date };13 }));14 return posts.sort((a, b) => +new Date(b.date) - +new Date(a.date));15}1/4Node's file system and path modules, plus gray-matter to read front matter.
gray-matter reads the title and date from the top of each file. Since this runs in Server Components, using the file system is fine.
Save yourself the pain
Common mistakes
Oops
Importing fs in a Client Component.
Do this instead
File system code only works on the server. Keep it in Server Components or lib files they call.
Oops
Using titles with spaces and capitals as URLs.
Do this instead
Turn titles into clean slugs like my-first-internship, and never change them after publishing.
Your mission
Milestone 1: three posts live
Quick check
Your posts come from a CMS that editors update a few times a day. What's a good choice?
Go deeper
- 1Use `generateStaticParams` to pre-render all post pages at build time.
- 2Add ISR so new posts (from a CMS or markdown files) appear without a full redeploy.
- 3Generate per-post metadata dynamically from the post's title and excerpt.
More projects at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.