September 23, 20226 min read

Gatsby with Netlify CMS

In this post, we will look closely at a Netlify CMS. It is an example of a new type of CMS that is git-based. We will integrate it with a Gatsby example project.

Last Updated September 23, 2022
Five metal gears on a black brackground
Photo by Miguel Á. Padriñán

If you’re a web developer, you probably recognize this image. Even if you’re not, you probably know what it is.

Wordpress Dahsboard

A WordPress dashboard - it’s an easy and intuitive way to manage content on your website. You don’t need to know PHP, MySQL, or HTML to create something like a blog post. There are multiple tabs, inputs, and buttons that help with creating content. The content creation experience must be good because it’s the most used CMS on the market. But, the popularity comes with a huge disadvantage - it’s a primary target for hackers and spammers. Security vulnerabilities are not the only cons, but this post is not about that.

Eventually, your content needs to be in HTML markup to be interpreted by a browser. You could code everything by yourself. I’m writing this blog post in MDX - a format that combines Markdown and JavaScript that you eventually see as an HTML website. Everything is static and safe. But it requires learning multiple syntaxes, and not everyone wants that. Also, it’s pretty easy to mess something up, so I wanted to check how Git-based CMS works.

Netlify CMS

Netlify CMS is an example of a Git-based CMS. The CMS uses the Git version control system under the hood. It allows you to keep everything in a Git repository - content alongside code. It has some advantages over standard CMSes like Worpdress. And it doesn’t compromise on ease of use. At its core, Netlify CMS is a React app that wraps Git workflow. So, you don’t need to learn Git, Yaml, or Markdown to use it. It offers a rich web UI, just like WordPress. It’s friendly for non-technical editors. But, you need some knowledge to configure it. So, I’ll integrate Netlify CMS with a Gatsby example project in this post. I’ll try to recreate a post from my blog.

If you want to see a bigger picture and how Gatsby or Netlify CMS fits into Jamstack architecture, I wrote a post about this.

How to use Gatsby with Netlify CMS?

We will start by initiating a new Gatsby project. You can create it with Gatsby CLI.

🔴 🟡 🟢
gatsby new netlify-cms-example

Then we need to install two packages: netlify-cms-app and gatsby-plugin-netlify-cms. The first is responsible for creating mentioned earlier app, and the second integrates it with Gatsby.

🔴 🟡 🟢
npm install netlify-cms-app gatsby-plugin-netlify-cms

A Gatsby plugin needs to be registered to work. We need to add a new dependency in the plugin array.

3module.exports = {
4 plugins: [`gatsby-plugin-netlify-cms`],

The plugin itself doesn’t require configuration, but Netlify CMS does. It doesn’t know what type of content you (or editors) will be creating. So, it needs a config.yml file with folders, collections, and different fields. For now, let’s copy an example config and paste it into the static/admin folder. Gatsby will copy everything from this folder to the output build.

3 name: test-repo
5media_folder: static/assets
6public_folder: /assets
9 - name: blog
10 label: Blog
11 folder: blog
12 create: true
13 fields:
14 - { name: path, label: Path }
15 - { name: date, label: Date, widget: datetime }
16 - { name: title, label: Title }
17 - { name: body, label: Body, widget: markdown }

Now we can run gatsby develop in the terminal. If you configured everything correctly, a similar web UI should greet you at http://localhost:8000/admin/.

Netlify CMS with default config

Netlify CMS config

I think it’s the right time to explore different configuration options. Here are a couple of important, general ones:

  • backend - specifies how to access the content of your website. It has the following options:
    • repo - path to repository (username/repo name).
    • branch - branch for storing content.
    • base_url - OAuth client hostname when using an external OAuth server.
    • cms_label_prefix - pull or merge requests label prefix when using editorial workflow.
  • publish_mode - allows you to enable editorial workflow - more stages before publication.
  • media_folder - a relative path to the folder for uploaded files.
  • public_folder - a path by which you can access uploaded files in the built site.
  • site_url - a URL to your published website.


There are specific options for collections. A collection is a list of objects of the same type. Blog posts, recipes, and products are good examples. Each configured collection displays on the left sidebar, as you saw. These settings describe the shape of your content.

  • name - unique identifier for a collection.
  • identifier_field - this field will be used (instead of the default) in slug creation if specified. Netlify CMS expects a title field by default.
  • label - label for the collection in the UI. It defaults to the name, but it doesn’t need to be the same.
  • label_singular - the same as above, but for individual elements. It defaults to the label.
  • description - it’s an optional description for the UI.
  • folder or files - a collection type. The folder option takes a path to a folder. Inside this folder, there should be multiple files with the same format and fields (e.g., blog posts). The files option contains uniquely configured files (e.g., the about page).
  • filter - it’s an option for the folder only. As the name suggests - it filters files from the folder. It takes field and value to use during filtration.
  • create - another option for the folder only. A true value allows users to create new items in the collection. false by default.
  • extension - used for finding and saving files in a folder collection.
  • format - used for parsing and saving files in a folder collection.
  • slug - a template for generating new filenames based on different fields. Inside this option, you can use multiple template tags, like:
    • {{slug}} - a URL-safe version of the title.
    • {{year}} - a year of the file creation date.
    • {{second}} - a second of the file creation date
    • {{field_name}} - beside defined tags, you can also use custom ones by wrapping the field name in double curly braces.
  • preview_path - a template for generating paths to content on the live site. The tags are the same as the previous ones with the exceptions:
    • {{slug}} - here, it means the entire slug for the current entry.
    • Date tags may require additional config.
    • {[dirname}} - path to the parent folder of the collection.
    • {{filename}} - the file name.
    • {{extension}} - the extension of the file.


Each collection element can have many fields. When you click to create a new collection element (“New Blog” in our case), you will see UI elements like this.

Default fields in Netlify CMS

It looks similar to standard CMS like WordPress. If you look closely at the previous config snippet and compare it with this screenshot, you should see that the fields option matches UI elements. The fields option maps UI widgets to values saved in a file. It takes a list of objects with the following options:

  • name - unique identifier for the field
  • label - label for the field in the UI.
  • widget - defines editor inputs and data types. It takes a string, which determines a widget type. There are default widgets like date, image, or markdown. Additional options allow customizing them. These options differ based on widget type, but there are also shared options like required or hint.
  • required - specifies if the field is required.
  • hint - it’s a helper text displayed below the UI element.
  • default - a default value for a field. Available for most widget types.
  • pattern - a list of regex and an error message - it’s used for field validation.

Blog posts in Netlify CMS

There was a lot to take, but I think we’re now ready to replace the default config with our custom. We want the ability to add, modify, and delete typical blog posts with titles, descriptions, images, tags, etc. Let’s start with configuring our collection.

3 - name: blog
4 label: Blog
5 label_singular: Post
6 folder: content/blog
7 create: true
8 delete: true
9 extension: markdown
10 format: frontmatter
11 slug: "{{slug}}"
12 preview_path: "blog/{{filename}}"
13 fields:
14 # Below

The name and the label fields can remain the same. I also added label_singular for individual posts. The CMS user is supposed to be able to create and delete posts. Posts should be in markdown format with additional information stored in frontmatter. We need to add fields to allow the user to populate this information. There should be a title field for slug creation. The description can be displayed or used in meta tags.

2 - { name: title, label: Title }
3 - { name: description, label: Description, widget: text }
4 - { name: date, label: Publication Date, widget: datetime }
5 - { name: updated, label: Update Date, widget: datetime }
6 - name: image
7 label: Featured Image
8 widget: object
9 summary: "{{fields.src}}"
10 fields:
11 - { name: src, label: Image source, widget: image }
12 - { name: alt, label: Alt text, widget: string }
13 - {
14 name: credit,
15 label: Author of the image,
16 widget: string,
17 required: false,
18 }
19 - {
20 name: tags,
21 label: Tags,
22 widget: select,
23 multiple: true,
24 options:
25 [
26 "Web Development",
27 "Design",
28 "Computer Science",
29 "Data Science",
30 "Mathematics",
31 ],
32 default: ["Computer Science"],
33 min: 1,
34 max: 4,
35 required: false,
36 }
37 - { name: body, label: Body, widget: markdown }

The user can pick dates with the datetime widget. The featured image needs to be an object and contain subfields to be accessible. After choosing a picture with the image widget, the user should add alt text and give credit to an author. I also added several tags with the select element to organize blog posts. The user will be writing post content inside the markdown element. After this configuration, our CMS looks like this:

Netlify CMS with custom config

Connecting Netlify CMS to Git repo

The user can use CMS to create blog posts, but entered information will only stay in a browser. We need a git repo to store this content. First, we need to connect our local repository to a service like GitHub. After doing that, let’s take a step back. Netlify CMS is a single-page web app, as mentioned earlier. So, we want to make changes to our repo from the browser. It requires authentication, and GitHub needs a server for this purpose. Netlify provides a free solution and can take care of this. Connecting the repository with Netlify is pretty straightforward. Make your account, go to Sites > Add new site > Import an existing project, and follow the steps. We can authenticate our deployed website with the OAuth setup. We need to add a new OAuth application in GitHub and save generated credentials to our site in Netlify. From now our CMS can make changes inside the repo. . .almost. We also need to supplement missing information in our config. Then we need to commit and push our changes to GitHub.

3 name: github
4 repo: your-username/repo-name
5 branch: main

Visit and your browser should display an authentication page like this.

Authentication in Netlify CMS

After logging in, you can create a blog post, populate its fields and click “publish now.” It will save your changes in the repository after a few seconds. Woohoo! We made it. “But. . .posts aren’t displayed on the website”, you may say pessimistically. I would respond - yeah, good point. However, the goal of this post was to integrate Netlify CMS with Gatsby. I wanted to keep everything else as simple as possible, so I started with a minimal setup. And if you started with a blog, you have this part already. This post is getting long, so I’ll end here. I may add a second part where we will display our posts.

Profile picture where I'm in a white t-shirt on gray gradient background. Half of my face is in the shadow. The other half is correctly illuminated.

Software engineer with polymath aspirations.

Read more. Stay curious

Half of a record on white background
September 1, 2022 • 4 min read

Accessible animations in React

Or how not to spin your users round (like a record). Some animations can make users sick. We'll take care of them and make non-essential animations optional.

Read post
List of CSS variables in Visual Studio Code.
September 14, 2022 • 4 min read

Converting design tokens to CSS variables with Node.js

Converting design tokens is an error-prone process - I found about it the hard way. So, I made a simple Node.js script that will help me with that task.

Read post
Question mark composed with dots on yellow background
July 23, 2022 • 3 min read

Is it native JavaScript? Isn’t it??

My first encounter with optional chaining and nullish coalescing operator.

Read post

A newsletter that sparks curiosity💡

Subscribe to my newsletter and get a monthly dose of:

  • Front-end, web development, and design news, examples, inspiration
  • Science theories and skepticism
  • My favorite resources, ideas, tools, and other interesting links
I’m not a Nigerian prince to offer you opportunities. I don’t send spam. Unsubscribe anytime.