This section will help you integrate Netlify CMS with a new or existing Jekyll project.
Jekyll is a blog-aware static site generator built with Ruby. Github Pages are powered by Jekyll, making it a popular choice for developer blogs and project pages.
If you're starting a new project, the fastest route to publishing on a Jekyll website with Netlify CMS is to deploy a template on Netlify.
This guide aims to be helpful for users in the following situations.
This guide will use the blog you get if you follow the really excellent official Jekyll step by step tutorial as a starting point. If you're new to Jekyll - I recommended you start by following the tutorial so you know your way around your new blog. Otherwise you can clone this repo and checkout the without-cms
branch.
You have lots of options for hosting and serving your project, but to for the sake of simplicity this guide will assume you follow this guide to create a remote git repository on Github and give Netlify access to build and serve the project when you push changes.
At this point you have a perfectly good Jekyll site published on the web. Congratulations! It looks great, and to update the content on your site you just open your favorite text editor, create or edit a markdown file, then commit your changes and push them to your remote git repository. But maybe you are tired of looking at markdown, or you find yourself wanting to update your blog from computers without your favorite text editor and tools installed, or you want to make it easier for less technical individuals to contribute to your blog. This is where Netlify CMS comes in.
admin
in the root directory of your Jekyll project. Jekyll will copy this directory to the _site
generated when the jekyll build
command is run.mkdir admin
index.html
cd admin && touch index.html
index.html
.<!-- admin/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
jekyll server
and open http://127.0.0.1:4000/admin
in your browser. You should see a page with following error message.Error loading the CMS configuration
Config Errors:
Error: Failed to load config.yml (404)
Check your config.yml file.
netlify-cms.js
will look for config.yml
at the root of the admin
directory. Let's add it now.touch config.yml
Go back to your browser and you should see the following errors.
Error loading the CMS configuration
Config Errors:
config should have required property 'backend'
config should have required property 'collections'
config should have required property 'media_folder'
config should have required property 'media_library'
config should match some schema in anyOf
Check your config.yml file.
Before we really dig into the configuration for our project, we'll start by setting the minimum configuration to satisfy Netlify CMS.
backend
property we'll use the test-repo backend. It will let us see the cms interface without connecting to a git repository.media_folder
property should be set to the path where you want the cms to save images. We'll follow the advice of the jekyll docs and create an assets/
directory. Setting the media_folder
property will take care of the media_library
property error as well.collections
property requires an array of collection objects. We'll start with a collection with only the property name
defined to see what else is required.Copy and paste the following into config.yml
# config.yml
backend:
name: test-repo
media_folder: "assets/"
collections:
- name: "blog"
Back in the browser you should see a new set of errors.
Error loading the CMS configuration
Config Errors:
'collections[0]' should have required property 'label'
'collections[0]' should have required property 'files'
'collections[0]' should have required property 'folder'
'collections[0]' should have required property 'fields'
'collections[0]' should match exactly one schema in oneOf
Check your config.yml file.
Great, now we're getting somewhere. Netlify CMS is telling us we need to define some properties of collection.
label
property is the string used to identify the collection in the cms UI. We'll set it to "Blog"
folder
should be set to the directory containing the files we want the cms to be able to create and edit. We'll start with "_posts/"
fields
property requires an array of field objects. We'll start with a collection with only the property name
defined. Setting the fields
property will take care of the files
property error as well.Update config.yml
like so.
# config.yml
backend:
name: test-repo
media_folder: "assets/uploads"
collections:
- name: "blog"
label: "Blog"
folder: "_posts/"
fields:
- { name: Title }
And in the browser you should see.
Log in and you should see.
Awesome, the CMS is running without errors! Great, but you might have noticed the CMS isn't displaying data from the three markdown files in the _posts/
directory. The reason is test-repo
uses local browser storage and doesn't have access to your file system. In fact, none of the Netlify CMS backends can interact with local git repositories. This is a common point of confusion and bears repeating: NETLIFY CMS CANNOT INTERACT WITH LOCAL GIT REPOSITORIES.
Next, we'll setup the Backend and Authentication so you can start updating content on your Jekyll site.
You have lots of options for giving Netlify CMS permission to push commits to your Jekyll blog repository. In this guide - we're using Netlify's Identity service.
test-repo
backend configuration git-gateway
//
# config.yml
backend:
name: git-gateway
branch: master # Branch to update (optional; defaults to master)
In your browser, go to https://app.netlify.com/sites/{YOUR_PROJECT_NAME}/settings/identity
Click Enable Identity
Scroll down to the Registration section and add external OAuth providers (optional)
Scroll down to the Services section and click Enable Git Gateway
Make the following changes to your Jekyll project in admin/index.html
and _layouts/default.html
. You can read more about the purpose of these changes here
Add the netlify-identity-widget.js
script to the head of admin/index.html
and _layouts/default.html
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
Add the following redirect script to the bottom of the body in _layouts/default.html
<script>
if (window.netlifyIdentity) {
window.netlifyIdentity.on("init", user => {
if (!user) {
window.netlifyIdentity.on("login", () => {
document.location.href = "/admin/";
});
}
});
}
</script>
Now in the browser you should see a modal asking for the URL of your Netlify site.
Once you've set it you should see a Signup/Login modal.
And once you've logged in you should see the CMS UI, now populated with the Jekyll blog posts you created in the Jekyll tutorial. Also note, when using the git-gateway
backend you'll be redirected to your live site when you login, meaning if you want to test your changes you'll need to push to your remote repository.
Click on one of the posts and you'll see the edit view.
Amazing! But the editor is missing some of the frontmatter fields in your markdown file, specifically the layout and author fields.
layout: post
author: jill
title: Bananas
Also, we still can't create new blog posts from the CMS. We'll address these issues and others in the next section.
We'll start by updating the blog
collection. Blogging is baked into into Jekyll, and the _posts/
directory uses some special conventions we'll need to keep in mind as we configure Netlify CMS. Copy and paste the following into your config.yml
.
collections:
- name: "blog"
label: "Blog"
folder: "_posts/"
create: true # Allow users to create new documents in this collection
slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
editor:
preview: false
fields: # The fields for each document, usually in front matter
- { label: "Layout", name: "layout", widget: "hidden", default: "post" }
- { label: "Title", name: "title", widget: "string" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- { label: "Body", name: "body", widget: "markdown" }
A few things to note.
create: true
set you'll be able to create new postsslug
to '{{year}}-{{month}}-{{day}}-{{slug}}'
because Jekyll requires this format for blog posts. year
, month
, and day
will be extracted from the date
field, and slug
will be generated from the title
field.editor
configuration with a field preview: false
. This will eliminate the preview pane. Because Jekyll uses Liquid templates, there currently isn't a good way to provide a preview of pages as you update the content.layout
field default is set to post
so Jekyll knows to use _layouts/post.html
when it renders a post. This field is hidden because we want all posts to use the same layout.date
and title
field will be used by the slug
- as noted above, Jekyll relies on the filename a post's publish date, but Netlify CMS does not pull date information from the filename and requires a frontmatter date
field. Note Changing the date
or title
fields in Netlify CMS will not update the filename. This has two implications...date
or title
fields in Netlify CMS, Jekyll won't noticedate
and title
fields for existing posts, but if you don't the date in the filenames and frontmatter will disagree in a way that might be confusing_posts
directoryIn addition to _posts
, the Jekyll tutorial blog includes a collection of authors in the _authors
directory. Before we can configure Netlify CMS to work with the authors
collection, we'll need to make a couple tweeks to our Jekyll blog. Here's the front matter for one of the authors.
short_name: jill
name: Jill Smith
position: Chief Editor
name
has special meaning as a unique identifier in Netlify CMS, but as set up now our Jekyll blog is using short_name
as the unique identifier for authors. For each author, update the frontmatter like so.
name: jill
display_name: Jill Smith
position: Chief Editor
then update _layouts/author.html
and staff.html
accordingly.
<!-- _layouts/author.html -->
--- layout: default ---
<h1>{{ page.display_name }}</h1>
<h2>{{ page.position }}</h2>
{{ content }}
<h2>Posts</h2>
<ul>
{% assign filtered_posts = site.posts | where: 'author', page.name %} {% for
post in filtered_posts %}
<li>
<a href="{{ site.baseurl }}{{ post.url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
<!-- staff.html -->
--- layout: default ---
<h1>Staff</h1>
<ul>
{% for author in site.authors %}
<li>
<h2>
<a href="{{ site.baseurl }}{{ author.url }}">{{ author.display_name }}</a>
</h2>
<h3>{{ author.position }}</h3>
<p>{{ author.content | markdownify }}</p>
</li>
{% endfor %}
</ul>
Next, copy and paste the following into the collections array in config.yml
below the blog
collection.
- name: "authors"
label: "Authors"
folder: "_authors/"
create: true
editor:
preview: false
fields:
- { label: "Layout", name: "layout", widget: "hidden", default: "author" }
- { label: "Short Name", name: "name", widget: "string" }
- { label: "Diplay Name", name: "display_name", widget: "string" }
- { label: "Position", name: "position", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
Now that we have the authors
collection configured, we can add an author
field to the blog
collection. We'll use the relation widget to define the relationship between blog posts and authors.
# updated fields in blog collection configuration
fields:
- { label: "Layout", name: "layout", widget: "hidden", default: "post" }
- { label: "Title", name: "title", widget: "string" }
- { label: "Publish Date", name: "date", widget: "datetime" }
- {
label: "Author",
name: "author",
widget: "relation",
collection: "authors",
displayFields: [display_name],
searchFields: [display_name],
valueField: "name",
}
- { label: "Body", name: "body", widget: "markdown" }
With that configuration added, you should be able to select the author for a post from a dropdown.
Our Jekyll blog includes an About page. It would nice to be able to edit that page just like we can edit our blog and author pages. Netlify CMS provides file collections to solve this problem.
Copy and paste the following into the collections array in config.yml
- name: "pages"
label: "Pages"
editor:
preview: false
files:
- label: "About Page"
name: "about"
file: "about.md"
fields:
- { label: "Title", name: "title", widget: "hidden", default: "about" }
- { label: "Layout", name: "title", widget: "hidden", default: "about" }
- { label: "Body", name: "body", widget: "markdown" }
The last aspect of our Jekyll blog we might want to bring under the control of Netlify CMS is our Navigation menu. Our Jekyll tutorial blog has a file _data/navigation.yml
that defines the links rendered by _includes/navigation.yml
. It looks like this.
# _data/navigation.yml
- name: Home
link: /
- name: About
link: /about.html
- name: Blog
link: /blog.html
- name: Staff
link: /staff.html
To make this file editable with Netlify CMS, we'll need to make one minor tweak. The issue is this file contains an yaml array at the top level, but Netlify CMS is designed to work with yaml objects. Update _data/navigation.yml
so it looks like so.
# _data/navigation.yml
items:
- name: Home
link: /
- name: About
link: /about.html
- name: Blog
link: /blog.html
- name: Staff
link: /staff.html
You'll need to update _includes/navigation.html
accordingly. {% for item in site.data.navigation %}
should be changed to {% for item in site.data.navigation.items %}
. When you're done, the nav html should look like this.
<nav>
{% for item in site.data.navigation.items %}
<a href="{{ site.baseurl }}{{ item.link }}" {% if page.url == item.link %}style="color: red;"{% endif %}>
{{ item.name }}
</a>
{% endfor %}
</nav>
Finally, add the following to the collections array in config.yml
- name: "config"
label: "Config"
editor:
preview: false
files:
- label: "Navigation"
name: "navigation"
file: "_data/navigation.yml"
fields:
- {
label: "Navigation Items",
name: "items",
widget: "list",
fields:
- {label: Name, name: name, widget: string}
- {label: Link, name: link, widget: string}
}
Now you can add, rename, and rearrange the navigation items on your blog.