Building a blog using Next.js and Markdown is a popular choice for developers who want a fast, SEO-friendly site with simple content management. Next.js offers powerful features like static site generation and server-side rendering, while Markdown allows easy writing and formatting of blog posts. This step-by-step guide shows you how to create a modern blog using these tools in 2025.
Create a Blog with Next.js
Step 1: Set Up Your Next.js Project
Start by creating a new Next.js app using the following command:
npx create-next-app my-blog cd my-blog
This sets up a basic Next.js project with everything you need.
Step 2: Install Required Dependencies
To work with Markdown files, install gray-matter
for parsing frontmatter and remark
for converting Markdown to HTML.
npm install gray-matter remark remark-html
Step 3: Create a Posts Directory
Inside your project root, create a posts
folder where you will store your Markdown files for blog posts.Example structure:
/my-blog /posts first-post.md second-post.md
Step 4: Write Your First Markdown Post
Create posts/first-post.md
with content like:
--- title: "My First Blog Post" date: "2025-07-20" --- Welcome to my first blog post using Next.js and Markdown! This setup makes content management easy and flexible.
Step 5: Fetch and Parse Markdown Posts
Create a utility function in lib/posts.js
to read Markdown files, parse frontmatter, and convert content to HTML.
import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; import { remark } from 'remark'; import html from 'remark-html'; const postsDirectory = path.join(process.cwd(), 'posts'); export function getSortedPostsData() { const fileNames = fs.readdirSync(postsDirectory); const allPostsData = fileNames.map(fileName => { const id = fileName.replace(/\.md$/, ''); const fullPath = path.join(postsDirectory, fileName); const fileContents = fs.readFileSync(fullPath, 'utf8'); const matterResult = matter(fileContents); return { id, ...matterResult.data }; }); return allPostsData.sort((a, b) => (a.date < b.date ? 1 : -1)); } export async function getPostData(id) { const fullPath = path.join(postsDirectory, `${id}.md`); const fileContents = fs.readFileSync(fullPath, 'utf8'); const matterResult = matter(fileContents); const processedContent = await remark() .use(html) .process(matterResult.content); const contentHtml = processedContent.toString(); return { id, contentHtml, ...matterResult.data }; }
Step 6: Display a List of Posts on the Home Page
Modify pages/index.js
to fetch and display post titles.
import { getSortedPostsData } from '../lib/posts'; import Link from 'next/link'; export async function getStaticProps() { const allPostsData = getSortedPostsData(); return { props: { allPostsData } }; } export default function Home({ allPostsData }) { return ( <main> <h1>My Blog</h1> <ul> {allPostsData.map(({ id, date, title }) => ( <li key={id}> <Link href={`/posts/${id}`}> <a>{title}</a> </Link> <br /> <small>{date}</small> </li> ))} </ul> </main> ); }
Step 7: Create Dynamic Routes for Individual Posts
Create a folder pages/posts
and add [id].js
:
import { getAllPostIds, getPostData } from '../../lib/posts'; export async function getStaticPaths() { const paths = getAllPostIds(); return { paths, fallback: false }; } export async function getStaticProps({ params }) { const postData = await getPostData(params.id); return { props: { postData } }; } export default function Post({ postData }) { return ( <article> <h1>{postData.title}</h1> <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} /> </article> ); }
Add the getAllPostIds
function in lib/posts.js
:
export function getAllPostIds() { const fileNames = fs.readdirSync(postsDirectory); return fileNames.map(fileName => { return { params: { id: fileName.replace(/\.md$/, '') } }; }); }
Step 8: Run Your Blog Locally
Start the development server with:
npm run dev
Visit http://localhost:3000
to see your blog in action. Click on posts to view their content rendered from Markdown.
Final Thoughts
Using Next.js with Markdown offers a fast, SEO-friendly, and easy-to-manage blogging solution. You can extend this setup with styling, pagination, comments, and more.