Learn how to create a Blog with Next.js and Markdown: A Step-by-Step Guide

Muhaymin Bin Mehmood

Muhaymin Bin Mehmood

· 2 min read
Learn how to create a Blog with Next.js and Markdown: A Step-by-Step Guide Banner Image
Learn how to create a Blog with Next.js and Markdown: A Step-by-Step Guide Banner Image

Building a blog with Next.js and Markdown allows you to create a fast, SEO-friendly site with a simple content management system. In this guide, we’ll walk you through setting up a Next.js project, integrating Markdown for content, and creating a blog website with dynamic routes and posts. By the end, you’ll have a fully functional blog that showcases Markdown posts.

1. Setting Up Your Next.js Project

1.1. Create a New Next.js Project

Start by setting up a new Next.js project using create-next-app.

npx create-next-app@latest my-blog
cd my-blog

1.2. Install Dependencies

You’ll need gray-matter to parse front matter in Markdown files and remark for processing Markdown.

npm install gray-matter remark remark-html

2. Adding Markdown Support

2.1. Create a Directory for Markdown Files

Create a folder named posts in the root directory of your project. This folder will contain your Markdown files.

mkdir posts

2.2. Add Sample Markdown Files

Create a sample Markdown file in the posts directory:

// posts/first-post.md
---
title: "My First Post"
date: "2024-09-01"
---

This is the content of my first post. Markdown allows you to **format** text, add [links](https://example.com), and more.

3. Parsing Markdown Files

3.1. Create a Utility Function to Load Posts

Create a lib directory and add a posts.js file to handle loading and parsing Markdown files.

// lib/posts.js
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

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 function getPostData(id) {
  const fullPath = path.join(postsDirectory, `${id}.md`);
  const fileContents = fs.readFileSync(fullPath, 'utf8');
  const matterResult = matter(fileContents);
  return {
    id,
    ...matterResult.data,
    content: matterResult.content,
  };
}

4. Building Pages and Components

4.1. Create the Home Page

Edit pages/index.js to display a list of blog posts.

// pages/index.js
import Link from 'next/link';
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}>
            <Link href={`/posts/${id}`}>
              <a>{title}</a>
            </Link>
            <br />
            <small>{date}</small>
          </li>
        ))}
      </ul>
    </div>
  );
}

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  return {
    props: {
      allPostsData,
    },
  };
}

4.2. Create Dynamic Post Pages

Add a [id].js file in the pages/posts directory for dynamic routes.

// pages/posts/[id].js
import { getAllPostIds, getPostData } from '../../lib/posts';

export default function Post({ postData }) {
  return (
    <div>
      <h1>{postData.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
    </div>
  );
}

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const postData = getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

4.3. Process Markdown Content

Modify lib/posts.js to include Markdown processing.

import remark from 'remark';
import remarkHtml from 'remark-html';

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(remarkHtml).process(matterResult.content);
  const contentHtml = processedContent.toString();
  return {
    id,
    contentHtml,
    ...matterResult.data,
  };
}

5. Styling Your Blog

5.1. Add Global Styles

Create a styles/globals.css file to include global styles.

/* styles/globals.css */
body {
  font-family: Arial, sans-serif;
  line-height: 1.6;
}

a {
  color: #0070f3;
}

a:hover {
  text-decoration: underline;
}

Import this CSS file in _app.js.

// pages/_app.js
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;

6. Conclusion

In this guide, you learned how to build a simple blog with Next.js and Markdown. You set up a Next.js project, integrated Markdown for content, and created dynamic routes for blog posts. You also learned how to style your blog and process Markdown content for display.

Muhaymin Bin Mehmood

About Muhaymin Bin Mehmood

Front-end Developer skilled in the MERN stack, experienced in web and mobile development. Proficient in React.js, Node.js, and Express.js, with a focus on client interactions, sales support, and high-performance applications.

Copyright © 2024 Mbloging. All rights reserved.