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, 2022If you're a web developer, you probably recognize this image. Even if you're not, you probably know what it is.
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 https://github.com/gatsbyjs/gatsby-starter-hello-world
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.
JS
1//gatsby-config.js23module.exports = {4 plugins: [`gatsby-plugin-netlify-cms`]5}
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.
YML
1#static/admin/config.yml2backend:3 name: test-repo45media_folder: static/assets6public_folder: /assets78collections:9 - name: blog10 label: Blog11 folder: blog12 create: true13 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 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.
Collections
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 atitle
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
orfiles
- a collection type. Thefolder
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). Thefiles
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 takesfield
andvalue
to use during filtration.create
- another option for the folder only. Atrue
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.
Fields
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.
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 fieldlabel
- 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 likerequired
orhint
.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.
YML
1#static/admin/config.yml2collections:3 - name: blog4 label: Blog5 label_singular: Post6 folder: content/blog7 create: true8 delete: true9 extension: markdown10 format: frontmatter11 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.
YML
1fields: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: image7 label: Featured Image8 widget: object9 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: false18 }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: false36 }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:
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.
YML
1#static/admin/config.yml2backend:3 name: github4 repo: your-username/repo-name5 branch: main
Visit https://your-website.netlify.app/admin/
and your browser should display an authentication page like this.
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.