Build a static blog from markdown files with Next.js

In this tutorial we’ll be building a blog using Next.js with the data for each of the individual blog posts loaded from markdown files. While there are many Next.js blog starter code bases available building from scratch is a great learning experience …


This content originally appeared on DEV Community and was authored by Michael Burrows

In this tutorial we’ll be building a blog using Next.js with the data for each of the individual blog posts loaded from markdown files. While there are many Next.js blog starter code bases available building from scratch is a great learning experience and shouldn’t take you long to get up and running.

Let’s get started by creating a new Next.js application:

npx create-next-app next-md-blog

We’ll also need a couple of dependencies so let’s go ahead and install those as well:

npm install gray-matter marked
  • gray-matter – Parses front-matter from markdown files.
  • marked – Compiles markdown into HTML.

Next let’s create a layout component that’ll load a global header and footer as is common practice when building a blog or websites in general. Create a new components folder with a Layout.js, Header.js and Footer.js files.

components/Layout.js

import Header from "./Header";
import Footer from "./Footer";

const Layout = (props) => (
  <>
    <Header />
    <main>{props.children}</main>
    <Footer />
  </>
);

export default Layout;

components/Header.js

import Link from "next/link";

const Header = () => {
  return (
    <header>
      <Link href="/">
        <a>Next.js Blog</a>
      </Link>
    </header>
  );
};

export default Header;

components/Footer.js

const Footer = () => {
  return (
    <footer>
      <p>&copy; {new Date().getFullYear()} - Powered by Next.js</p>
    </footer>
  );
};

export default Footer;

Next let’s create a sample markdown file for a blog post. This along with all subsequent blog post markdown files will need to be saved inside a new posts folder.

posts/hello-world.md

---
title: 'Hello World'
teaser: 'This is a short teaser for the first blog post.'
published: 'January 1, 2021'
thumbnail: '/images/stock-01.jpg'
---

Accusamus perferendis **voluptatibus** enim et. Cupiditate dolorum
delectus temporibus in [earum cumque](https://w3collective.com) sunt 
qui. Quia quidem dolores delectus ut beatae id. Totam eius labore ut. 
Dolores doloribus ut ab minima fugiat eum atque. Sit ullam vel itaque 
minima non officia sunt ab.

The images folder for the thumbnails should be located within the public folder in the root of the application. Create a couple more files like this and then we’re ready to create a Post.js component that’ll display teasers for each of these blog posts on the homepage.

components/Post.js

import Link from "next/link";

export default function Post({ post }) {
  return (
    <div className="post-teaser">      
      <Link href={`/blog/${post.slug}`}>
        <a><h3>{post.frontmatter.title}</h3></a>
      </Link>
      <img src={post.frontmatter.thumbnail} />
      <p>{post.frontmatter.published}</p>
      <p>{post.frontmatter.teaser}</p>
      <hr />
    </div>
  );
}

Here we’re getting the front matter data (title, teaser, published, thumbnail) and outputting that data inside some HTML markup. Now to start pulling everything together by updating the pages/index.js file as follows:

import Head from "next/head";
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import Layout from "../components/Layout";
import Post from "../components/Post";

export default function Index({ posts }) {
  return (
    <>
      <Head>
        <title>Next.js Blog</title>
        <meta name="description" content="A simple blog powered by Next.js" />
      </Head>
      <Layout>
        <div className="posts">
          {posts.map((post, index) => (
            <Post post={post} key={index} />
          ))}
        </div>
      </Layout>
    </>
  );
}

export async function getStaticProps() {
  const files = fs.readdirSync(path.join("posts"));
  const sortOrder = (a, z) => {
    return new Date(z.frontmatter.published) - new Date(a.frontmatter.published)
  }
  const posts = files.map((filename) => {
    const slug = filename.replace(".md", "");
    const markdown = fs.readFileSync(
      path.join("posts", filename),
      "utf-8"
    );
    const { data: frontmatter } = matter(markdown);
    return {
      slug,
      frontmatter,
    };
  });
  return {
    props: {
      posts: posts.sort(sortOrder),
    },
  };
}

Now all that’s left it to create the file to display the individual blog posts.

pages/blog/[slug].js

import fs from "fs";
import path from "path";
import matter from "gray-matter";
import marked from "marked";
import Head from "next/head";
import Layout from "/components/Layout";

export default function Post({
  frontmatter: { title, published, teaser },
  content,
}) {
  return (
    <>
      <Head>
        <title>{title}</title>
        <meta name="description" content={teaser} />
      </Head>
      <Layout>
        <h1>{title}</h1>
        <p>{published}</p>
        <div dangerouslySetInnerHTML={{ __html: marked(content) }}></div>
      </Layout>
    </>
  );
}

export async function getStaticPaths() {
  const files = fs.readdirSync(path.join("posts"));
  const paths = files.map((filename) => ({
    params: {
      slug: filename.replace(".md", ""),
    },
  }));
  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params: { slug } }) {
  const markdown = fs.readFileSync(path.join("posts", slug + ".md"), "utf-8");
  const { data: frontmatter, content } = matter(markdown);
  return {
    props: {
      frontmatter,
      slug,
      content,
    },
  };
}

That’s all for this tutorial, you should now have a functioning blog using Next.js which you can easily add new posts using markdown files. We’ve only just scratched the surface of what’s possible with Next.js, we’ll be publishing many more tutorials on the topic so stay tuned.


This content originally appeared on DEV Community and was authored by Michael Burrows


Print Share Comment Cite Upload Translate Updates
APA

Michael Burrows | Sciencx (2021-10-26T05:23:45+00:00) Build a static blog from markdown files with Next.js. Retrieved from https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/

MLA
" » Build a static blog from markdown files with Next.js." Michael Burrows | Sciencx - Tuesday October 26, 2021, https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/
HARVARD
Michael Burrows | Sciencx Tuesday October 26, 2021 » Build a static blog from markdown files with Next.js., viewed ,<https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/>
VANCOUVER
Michael Burrows | Sciencx - » Build a static blog from markdown files with Next.js. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/
CHICAGO
" » Build a static blog from markdown files with Next.js." Michael Burrows | Sciencx - Accessed . https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/
IEEE
" » Build a static blog from markdown files with Next.js." Michael Burrows | Sciencx [Online]. Available: https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/. [Accessed: ]
rf:citation
» Build a static blog from markdown files with Next.js | Michael Burrows | Sciencx | https://www.scien.cx/2021/10/26/build-a-static-blog-from-markdown-files-with-next-js/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.