Starter code for a static blog using Next.js and MDX

This kit is designed to give you a fully functional, easy to use (if you are a developer) blog with perfect Lighthouse scores.

Lighthouse audit with 100% scores.

The idea is to provide a complete blogging system that requires only two things from the developer:

  1. write some posts; share you knowledge!
  2. style the blog to make it your own

And, of course, this repo could merely be a starting point for your hacking. Hack away and have fun.

To clone this repo:

git clone --depth=1 

Feature list:

  • Static website deployment
  • Write your posts in markdown, and use React components in your markdown thanks to MDX. Or use plain React, if you prefer.
  • A CLI for creating new pages or posts. It processes all the necessary meta data for creating the blog list and adding SEO data to all pages.
  • Perfect Lighthouse scores.
  • Excellent SEO
  • Service Worker that caches all pages and posts for offline reading
  • Tag search
  • reading progress indicator on posts (optional/configurable)
  • Code syntax highlighting
  • Smooth scroll links
  • Optimized images
  • Tests are set up using Jest
  • Easy deploys with Zeit’s Now


This blog processes pages based on the meta data found in the page and post component files. To make sure you include all necessary meta data, and that page/post components conform to the requirements of the BlogEngine and its utility functions, it is important to use the CLI to scaffold all new pages and posts.

There are two ways to use the CLI:

  1. Install the CLI so you can use the blog keyword.
    • This allows you to use commands like blog -t post -m
  2. Use the file as a script.
    • This allows you to use commands like ./cli.js -t post -m

1. Install: CLI with keyword

At the root of the project, in your terminal run the command npm link or sudo npm link. This will allow you to use the blogkeyword when using the CLI.

If you have trouble installing the CLI, skip the installation and use the file as a script (see #2 below).

2. No Install: CLI file as script

At the root of the project, in your terminal run the command chmod +x ./cli.js or sudo chmod +x ./cli.js. This allows you to use the CLI like a script: ./cli.js <your-flags-and-options-here>.

CLI Flags

To list the flags and their descriptions, run one of the following commands in the root of the project:

  1. blog help
  2. ./cli.js help

Either of those commands will display:

      -t  ["template"  | String  | either "page" or "post"]
      -m  ["mdx file"  |   n/a   | if present file will be .mdx, else .js]
      -f  ["file name" | String  | e.g. "how-to-build-a-nextjs-app"]

Creating pages and posts

The basic difference between a page and a post is that a page lives inside the pages/ directory, whereas a post lives in the pages/blog/ directory. Only post files are included in the blog post list at /blog. Use the -t flag to indicate whether you want to create a new page or a new post.

blog -t page -f newPage // this creates a page named "newPage.js"
blog -t post            // this creates a JavaScript post with a randomized file name

As you can see above, the -f flag allows you to name your new file. Your page/post component name will also be the url to that page/post, so name your components strategically. For example, a page named my-page.js will have the url A post named my-post.mdx will have the url

If you omit the -f flag, the CLI will generate a file name for you but you should rename it immediately.

You also have the option of using a MDX file or a JavaScript file for your new page/post.

blog -t page -m // this creates a MDX file with a randomized name
blog -t page -f contact   // this creates a JavaScript file named contact.js

Meta Data

Each page/post needs to export (not default export) a meta object. The required fields for content are:

title: "Title of Page/Post goes here",
tags: ["tag-1", "tag-2"],
layout: "page",
publishDate: "2011-01-01",
modifiedDate: false,
seoDescription: "In this post I  with . And blah blah."
  • title: The title displayed on the page. It is also used for SEO.
  • tags: This array enables the tag search page. The tags are also used in the SEO header property: <meta name="keywords" content={stringOfAllPostTags} />.
  • layout: This is used in the utils/render-app-layout.js function. There are currently four layouts (and a default layout): "blog-post-list""post""page" and "search".
  • publishDate: This is displyed on blog posts. It is also used for SEO. Must be in “YYYY-MM-DD” format.
  • modifiedDate: Used for SEO. Include this if the post has been modified. If it has not been modified, leave it out or give it the value false.
  • seoDescription: Used for SEO.

Blog posts have optional meta properties. These optional fields are:

  • exclude: Set this property to true if you do not want it to appear on the blog post list on the /blog page.
  • hideProgressBar: Set this property to true if you do not want the reading progress bar for a particular blog post.

If you do not include the optional properties for a blog post, they are assumed to be false.

BlogMeta Component

This component should be added to each blog post after the meta export. Make sure there is an empty line between the meta export and <BlogMeta />, otherwise the MDX parser will throw an error. To illustrate:

import BlogMeta from "../../components/BlogMeta";
export const meta = {
    title: "Third Post With Image",
    tags: ["mdx", "javascript"],
    layout: "post",
    publishDate: "2017-12-10",
    hideProgressBar: true,
    seoDescription: "This post demonstrates a photo embed and Twitter card."

All this is added for you when you use the CLI, but it’s good to know these requirements exist in case you create posts without the CLI.

Subscribe to the Newsletter

Get our latest news,tutorials,guides,tips & deals delivered to your inbox.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.