Build a free blog with Next.js and Netlify CMS (2024)

Siddharth Roy

Posted on • Updated on • Originally published at siddharthroy.ml

Build a free blog with Next.js and Netlify CMS (3) Build a free blog with Next.js and Netlify CMS (4) Build a free blog with Next.js and Netlify CMS (5) Build a free blog with Next.js and Netlify CMS (6) Build a free blog with Next.js and Netlify CMS (7)

#netlify #nextjs #blog #javascript

Table of contents

  • Table of contents
  • What is Next.js
  • What is Netlify CMS
  • Why Next.js and Netlify CMS
  • Getting Started
  • Home Page
  • Listing Blogs
  • Blog Page
  • Connecting Netlify CMS
  • The end

What is Next.js

Next.js is a React Framework for building fast SEO-friendly websites. It supports serverside rendering, static site generation, optimizations, and much more. Basically, you can write serverside web apps using React which is necessary for building a blog because every page will be pre-rendered which is necessary for SEO. You will learn more about Next.js and how it works in this tutorial below.

What is Netlify CMS

It's a git-based Headless CMS build using React. It provides a rich text editor, real-time preview, media uploads all for free If you are hosting your site on Netlify.

Why Next.js and Netlify CMS

If you are a React Developer and want to build a website with a CMS but hate WordPress then Next.js with Netlify CMS is the best option for you.

If you want to check the final product, go ahead! here is the live site and the repo.

Getting Started

Getting set up Next.js is simple, enter this command and it will set up a basic Next.js project for you:

npx create-next-app nextjs-blog# oryarn create next-app nextjs-blog

After the setup is complete cd into the folder and run this command to start the app in the development server:

cd nextjs-blogyarn dev# ornpm dev

Visit localhost:3000 to view your app

Build a free blog with Next.js and Netlify CMS (8)

If you look at the folder you will see 3 folders:

  1. pages
  2. public
  3. styles

They are pretty self-explanatory, I don't think I need to explain what they do.

Inside the pages folder, you will notice an API folder. This is for writing REST API and we will not use this folder for this project so you can delete that.

The _app.js this is the entry point of our app just like index.js in create-react-app.

The index.js returns a react component and it will render when you visit the front page of the app.

Routing in Next.js is different from traditional create-react-app, we do not use react-router here instead we create a new react component in the pages folder with the name of route as the filename. For example, create a new file testpage.js in the pages folder with the following:

export default function Testpage() { return ( <div> <p>Hello</p> </div> )}

Here the name of the function doesn't matter.

Now if you visit localhost:300/testpage you will see this

To learn more about pages check out Next.js Docs

Build a free blog with Next.js and Netlify CMS (9)

Each page is associated with a route based on its filename.

Home Page

Now it's time to make our Home Page to show the list of blogs.

First, replace everything in the index.js with this:

import styles from '../styles/Home.module.css'export default function Home() { return (<div className={styles['container']}> <h1 className={styles['header']}>Welcome to my blog</h1> <p className={styles['subtitle']}>This is a subtitle idk what to type here</p> <ul className={styles['blog-list']}> <li>A cool blog</li> <li>How to train a dragon</li> <li>How to catch a pokemon</li> </ul> </div>)}

If you are wondering what is happening in the first line, Next.js allows us to import CSS files as a module then you can access the classes as a key from styles. The name of the CSS file must end with .module.css for it to work. This allows you to use the same CSS class name in different files without worrying about collisions.

Then replace everything in the Home.module.css file in the styles folder with this:

.container { text-align: center; padding-top: 10rem; color: #445566;}.header { font-size: 3rem;}.subtitle { margin-bottom: 2rem;}.blog-list { text-align: start; margin: auto; width: max-content;}.blog-list a { color: rgb(4, 165, 165); text-decoration: underline;}

Now it should look like this

Build a free blog with Next.js and Netlify CMS (10)

Listing Blogs

Now It's time to add some dummy blogs and list them on Home Page.

First, make a new folder at the root of the project called content.

Note: The name of this folder doesn't matter, you can rename it to anything but make sure to modify the code below accordingly.

Inside the content folder create another folder named blogs this is where we are going to store all our blogs in markdown files.

Inside the blogs folder create a file named my-first-blog.md and fill it with this:

---title: "My First Blog"date: 24, August, 2021---# Welcome to my blogThis is an markdown file with some front matter.Yes you have key value pair in yaml format covered by --- on the of markdown file.The yaml style key value pair on the top is called front matter.## Header 2Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.> a blockquote

Before listing our newly created blog on my Home Page we have to install a library to parse the "front matter".

npm install gray-matter# oryarn add gray-matter

Then modify the index.js file to look like this:

import fs from 'fs'import matter from 'gray-matter'import Link from 'next/link'import Head from 'next/head'import styles from '../styles/Home.module.css'export default function Home({ blogs }) { return (<div className={styles['container']}> <Head> <title>Demo Blog</title> </Head> <h1 className={styles['header']}>Welcome to my blog</h1> <p className={styles['subtitle']}>This is a subtitle idk what to type here</p> <ul className={styles['blog-list']}> {blogs.map(blog => ( <li key={blog.slug}> <Link href={`/blog/${blog.slug}`}> <a>{blog.date}:{blog.title}</a> </Link> </li> ))} </ul> </div>)}export async function getStaticProps() { // List of files in blgos folder const filesInBlogs = fs.readdirSync('./content/blogs') // Get the front matter and slug (the filename without .md) of all files const blogs = filesInBlogs.map(filename => { const file = fs.readFileSync(`./content/blogs/${filename}`, 'utf8') const matterData = matter(file) return { ...matterData.data, // matterData.data contains front matter slug: filename.slice(0, filename.indexOf('.')) } }) return { props: { blogs } }}

Explanation:

  • In a typical create-react-app, all the rendering happens at the client-side but Next.js allows us to pre-render pages and it has two forms Static Generation (Using getStaticProps) and Server Side Rendering (Using getServerSideProps). Learn more
  • In the getStaticProps function, we are listing all the files in the blogs folder, parse the front matter and slug based on filename, and return them.
  • In the Home component, we are simply listing all the blogs from the blogs array that is given from getStaticProps and using Link Component from Next.js for fast client-side page transition.
  • We are using Head component from next/head to set the title of the page.

Let's check how it looks on the browser.

Build a free blog with Next.js and Netlify CMS (11)

Looks good but If you click on that link, it will show a 404 page. Let's fix that.

Blog Page

Our blog page is a dynamic page and to create a dynamic page in Next.js first create a folder named blog in the pages folder then inside blog create a file [slug].js this will match to /blog/:slug route.

Before we write anything, we need to install a library to render markdown.

 yarn add react-markdown@6.0.3 # or npm install react-markdown@6.0.3

Note: It's important to install that specific version because later versions don't work with Next.js

Now put this into the [slug].js file.

import fs from 'fs'import ReactMarkdown from 'react-markdown'import matter from 'gray-matter'import Head from 'next/head'export default function Blog({ frontmatter, markdown}) { return ( <div> <Head> <title>Demo Blog | {frontmatter.title}</title> </Head> <h1>{frontmatter.title}</h1> <span>{frontmatter.date}</span> <hr /> <ReactMarkdown> {markdown} </ReactMarkdown> </div> )}export async function getStaticProps({ params: { slug } }) { const fileContent = matter(fs.readFileSync(`./content/blogs/${slug}.md`, 'utf8')) let frontmatter = fileContent.data const markdown = fileContent.content return { props: { frontmatter, markdown } }}export async function getStaticPaths() { const filesInProjects = fs.readdirSync('./content/blogs') // Getting the filenames excluding .md extension // and returning an array containing slug (the filename) as params for every route // It looks like this // paths = [ // { params: { slug: 'my-first-blog' }}, // { params: { slug: 'how-to-train-a-dragon' }}, // { params: { slug: 'how-to-catch-a-pokemon' }}, // ] const paths = filesInProjects.map(file => { const filename = file.slice(0, file.indexOf('.')) return { params: { slug: filename }} }) return { paths, fallback: false // This shows a 404 page if the page is not found }}

Explanation:

  • In the getStaicProps we are simply getting the slug param and parsing the front matter and markdown from the file.
  • Because we are using getStaticProps on a dynamic page, Next.js expects us to provide the list of paths using getStaticPaths that have to be rendered at build time by returning the paths array with the required params in each.
  • In the Blog component, we are using react-markdown to convert markdown to HTML.
  • And again we are using the Head component to set the title for SEO.

Now if you visit our blog it will look like this:

Build a free blog with Next.js and Netlify CMS (12)

I will not go into the styling here because the blog is getting too long. But if you want to see the final version with styling included, go ahead.

Connecting Netlify CMS

Netlify CMS only works with websites that are hosted on Netlify. First, push your code to Github then log in to Netlify, and click "New site from git" and follow the prompts to select your repo. All the build settings should already be filled out for you.

Build a free blog with Next.js and Netlify CMS (13)

Click on deploy and within a minute your site will be live.

Now finally we can connect Netlify CMS to our blog. Create a folder named admin inside public folder, Inside admin folder create two files index.html and config.yml with the following:

index.html

<!doctype html><html><head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script> <title>Content Manager</title></head><body> <!-- Include the script that builds the page and powers Netlify CMS --> <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script></body></html>

config.yml

backend: name: git-gateway branch: main # Branch to update (optional; defaults to master)media_folder: "public/uploads" # Where media files will be storedpublic_folder: "/uploads" # Where the media files can be accesed from the serverpublish_mode: editorial_workflow # For Draftscollections: - name: "blog" # Used in routes, e.g., /admin/collections/blog label: "Blog" # Used in the UI folder: "content/blogs" # The path to the folder where the documents are stored create: true # Allow users to create new documents in this collection slug: "{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md fields: # The fields for each document, usually in front matter - {label: "Title", name: "title", widget: "string"} - {label: "Publish Date", name: "date", widget: "datetime", date_format: "DD.MM.YYYY", time_format: "HH:mm", format: "LLL"} - {label: "Body", name: "body", widget: "markdown"}

Learn more about how it works here.

For this to work, we also need to import the Netlify Identity widget in the head tag of every page. To do that create _document.js inside pages folder with this:

import Document, { Html, Head, Main, NextScript } from 'next/document'class MyDocument extends Document { render() { return ( <Html> <Head> {/* Netlify Widget */} <script async src="https://identity.netlify.com/v1/netlify-identity-widget.js" /> </Head> <body> <Main /> <NextScript /> <script dangerouslySetInnerHTML={{ __html: ` if (window.netlifyIdentity) { window.netlifyIdentity.on("init", user => { if (!user) { window.netlifyIdentity.on("login", () => { document.location.href = "/admin/"; }); } }); } `}}/> </body> </Html> ) }}export default MyDocument

Learn more about _document.js In Netlify Docs

Push this to Github and Netlify will automatically re-build the site for you.

Open the site setting in Netlify and enable Identity.

Build a free blog with Next.js and Netlify CMS (14)

And after that also enable Git Gateway on the same page.

Build a free blog with Next.js and Netlify CMS (15)

Now if you visit your website and go to the /admin page you will be greeted with Log In and Sign Up Prompt. Go ahead and Sign Up and confirm your email. After you have successfully created your account close the registration in the Site settings so no one can make an account and access the admin panel.

Build a free blog with Next.js and Netlify CMS (16)

The end

There you go you have made a Next.js powered Markdown blog, backed with a free CMS. If you did everything correctly you will see an admin panel upon visiting /admin page.

Build a free blog with Next.js and Netlify CMS (17)

Whenever you update or create a blog Netlify CMS will push the change to Github and Netlify will re-build your site.

If you got stuck here is the link to the repo.

Build a free blog with Next.js and Netlify CMS (2024)

References

Top Articles
Latest Posts
Article information

Author: Stevie Stamm

Last Updated:

Views: 6135

Rating: 5 / 5 (60 voted)

Reviews: 83% of readers found this page helpful

Author information

Name: Stevie Stamm

Birthday: 1996-06-22

Address: Apt. 419 4200 Sipes Estate, East Delmerview, WY 05617

Phone: +342332224300

Job: Future Advertising Analyst

Hobby: Leather crafting, Puzzles, Leather crafting, scrapbook, Urban exploration, Cabaret, Skateboarding

Introduction: My name is Stevie Stamm, I am a colorful, sparkling, splendid, vast, open, hilarious, tender person who loves writing and wants to share my knowledge and understanding with you.