Building a Blog with Next.js and Markdown
Learn how to create a powerful, fast, and SEO-friendly blog using Next.js and Markdown.
Introduction
Blogs are a fantastic way to share knowledge, insights, and experiences, and creating one can be an exciting project for any developer. With modern tools like Next.js and Markdown, building a blog has never been easier. Next.js, a powerful React framework, offers great features for server-side rendering (SSR), static site generation (SSG), and dynamic content handling. Markdown, a lightweight markup language, allows you to write content in a simple and readable format while retaining flexibility in structuring and displaying that content.
In this tutorial, we will walk through how to build a blog from scratch using Next.js and Markdown. We will cover everything from setting up your development environment to deploying the blog on a hosting platform like Vercel.
Main Content
1. Setting Up the Project
Before we begin writing our blog, we need to set up a new Next.js project. Here’s how:
Create a Next.js app: Run the following command to create a new Next.js app using
create-next-app
.npx create-next-app@latest my-nextjs-blog cd my-nextjs-blog
Install dependencies: We will use a package called
gray-matter
to parse the front matter (metadata) of our Markdown files andremark
to transform the content into HTML.Install them with:
npm install gray-matter remark remark-html
Create directories: Organize the project structure. Inside your project, create a
posts
directory where we will store our Markdown files.mkdir posts
2. Writing Markdown Files
Markdown files are simple text files that can contain both content and metadata. For our blog posts, we will add metadata in the form of front matter at the top of each Markdown file. Here’s an example of what a Markdown file might look like:
Example: first-post.md
---
title: "My First Blog Post"
date: "2025-01-01"
description: "This is the description of my first blog post."
---
# Welcome to my blog!
This is my first post using Next.js and Markdown. It's easy to build and render!
The part between
---
is the front matter, which contains metadata like the post title, date, and description.Below the front matter is the actual content of the post written in Markdown.
3. Fetching Markdown Files in Next.js
Next, we need to read and fetch the Markdown files from our posts
folder. This will allow us to dynamically load each blog post’s content. In Next.js, we will do this inside the getStaticProps
function for static site generation.
Create a file lib/posts.js
to handle loading the Markdown files:
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import { remark } from 'remark';
import remarkHtml from 'remark-html';
const postsDirectory = path.join(process.cwd(), 'posts');
export function getSortedPostsData() {
// Get file names under the posts directory
const fileNames = fs.readdirSync(postsDirectory);
const allPostsData = fileNames.map(fileName => {
// Remove the ".md" extension
const id = fileName.replace(/\.md$/, '');
// Read markdown file as string
const fullPath = path.join(postsDirectory, fileName);
const fileContents = fs.readFileSync(fullPath, 'utf8');
// Parse the post metadata
const { data } = matter(fileContents);
return {
id,
...data,
};
});
// Sort posts by date
return allPostsData.sort(({ date: a }, { date: b }) => {
if (a < b) {
return 1;
} else if (a > b) {
return -1;
} else {
return 0;
}
});
}
export async function getPostData(id) {
const fullPath = path.join(postsDirectory, `${id}.md`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
// Parse the post metadata and content
const { data, content } = matter(fileContents);
// Use remark to convert markdown to HTML
const processedContent = await remark()
.use(remarkHtml)
.process(content);
const contentHtml = processedContent.toString();
return {
id,
contentHtml,
...data,
};
}
Explanation:
getSortedPostsData
reads all the Markdown files and sorts them by date.getPostData
fetches the individual content of a post, processes the Markdown content usingremark
to convert it into HTML, and returns it.
4. Displaying Posts on the Home Page
To display the list of blog posts on the homepage, modify pages/index.js
:
import { getSortedPostsData } from '../lib/posts';
export default function Home({ allPostsData }) {
return (
<div>
<h1>My Blog</h1>
<ul>
{allPostsData.map(({ id, title, date }) => (
<li key={id}>
<a href={`/posts/${id}`}>
<h2>{title}</h2>
<small>{date}</small>
</a>
</li>
))}
</ul>
</div>
);
}
export async function getStaticProps() {
const allPostsData = getSortedPostsData();
return {
props: {
allPostsData,
},
};
}
Explanation:
We fetch all the blog post data using
getSortedPostsData
and pass it as a prop to the component.Each blog post title is rendered as a link to the individual post page.
5. Displaying Individual Blog Posts
To display individual blog posts, create a dynamic page under pages/posts/[id].js
:
import { getPostData } from '../../lib/posts';
export default function Post({ postData }) {
return (
<article>
<h1>{postData.title}</h1>
<div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
</article>
);
}
export async function getStaticPaths() {
const paths = getSortedPostsData().map(post => ({
params: { id: post.id },
}));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const postData = await getPostData(params.id);
return {
props: {
postData,
},
};
}
Explanation:
getStaticPaths
generates paths for each blog post based on the Markdown file names.getStaticProps
fetches the post data usinggetPostData
and renders it.
Examples/Case Studies
Example 1: A Simple Personal Blog
Consider a personal blog where each post showcases tips for web development. Using the structure above, you could easily manage and display multiple posts. Markdown makes it simple to write and format each post, and Next.js ensures fast page loading through static generation.
Example 2: A Developer’s Portfolio Blog
A developer could use the same structure to maintain a blog portfolio of personal projects and tutorials. Markdown allows you to easily create technical write-ups, and Next.js makes the site highly performant with static site generation.
Tips/Best Practices
Use Markdown Linting: To maintain consistency in your Markdown files, consider using a linter to enforce rules.
Optimize Images: If you’re embedding images in your posts, use Next.js' built-in
next/image
component for automatic optimization.Customizing the Markdown Renderer: Extend the Markdown processing pipeline to handle additional syntax, such as custom components for code snippets or embeds.
SEO Optimization: Use the
next/head
component to add meta tags and improve SEO.
Conclusion
Building a blog with Next.js and Markdown is an efficient and scalable way to create a content-driven website. By leveraging Next.js's powerful static site generation features and Markdown’s simple yet flexible syntax, you can create a fast, SEO-friendly blog with ease.
Are you ready to start building your own blog with Next.js and Markdown? Follow the steps above and create your own blog today! Feel free to customize it with your own features and design. If you need help, check out the official documentation or reach out to the community for support.