DEV Community

Cover image for DRY Netlify CMS config with Manual Initialization
Wojciech Kałużny
Wojciech Kałużny

Posted on • Originally published at mrkaluzny.com

DRY Netlify CMS config with Manual Initialization

In 2019 I absolutely fell in love with JAMStack and static websites. My love blossomed since I've encountered Gatsby. For a lot of websites out there, there is simply no better way to do create a website. Both this website and my company's - Clean Commit - are using Gatsby with Netlify CMS.

Static websites are steadily growing as a percent of projects we work on. Having experience using Gatsby paired with Netlify CMS I found a couple tweaks that should optimize your development experience with CMS configuration.

Netlify CMS's YAML configuration can quickly become a mess

If you had the pleasure (or rather, displeasure) of working with fairly complex content in Netlify CMS you know the config.yml file can grow quickly. One of the projects I worked on was a website for Dionysus - a company that specializes in organizing cultural events. This website contains 100s of events that are interconnected. At one point events were separated into different content types. Maintaining that CMS setup with YAML content quickly turns into a mess.

How to solve this issue? Manual Initialization!

Easy. Instead of YAML, we can use JavaScript to configure Netlify CMS with Manual Initialization. Setting up manual initialization is easy.

To enable manual initialization you need to create a JS file with the configuration and let Netlify CMS know to use it.

{
    resolve: 'gatsby-plugin-netlify-cms',
        options: {
            manualInit: true,
        modulePath: `${__dirname}/src/cms/cms.js`,
      },
    },
}
Enter fullscreen mode Exit fullscreen mode

I strongly suggest keeping all configuration files within src/cms to keep them well organized.

To use Netlify CMS with manual initialization, you also need to set up the general CMS settings.

import CMS from 'netlify-cms-app'
import pages from '@/cms/pages'
import posts from '@/cms/collections/posts'

window.CMS_MANUAL_INIT = true

CMS.init({
  config: {
    load_config_file: false,
    backend: {
      name: 'git-gateway',
      branch: 'master',
    },
    media_folder: '/static/img',
    public_folder: '/img',
    collections: [pages, posts],
  },
})
Enter fullscreen mode Exit fullscreen mode

Organizing posts and pages with Netlify CMS

When using manual initialization with Netlify CMS I divide settings into 3 groups - pages (for unique pages), collections, and partials. Sometimes we need to add additional groups like settings.

Setting up pages is mostly straight-forward. The main file I use to control pages is src/cms/pages/index.js.

import home from '@/cms/pages/home'
import blog from '@/cms/pages/blog'
import about from '@/cms/pages/about'
import privacy from '@/cms/pages/privacy'

const pages = {
  name: 'pages',
  label: 'Pages',
  files: [home, about, blog, privacy],
}

export default pages
Enter fullscreen mode Exit fullscreen mode

The main pages file is used to organize page order in the CMS and loading new pages.

import seo from '@/cms/partials/seo'
import SmallHero from '@/cms/partials/sections/small-hero'

const page = {
  file: 'content/pages/home.md',
  label: 'Home',
  name: 'Home',
  fields: [
    {
      label: 'Layout',
      name: 'layout',
      widget: 'hidden',
      default: 'contact',
    },
    {
      label: 'Type',
      name: 'type',
      widget: 'hidden',
      default: 'page',
    },
    {
      label: 'Title',
      name: 'title',
      widget: 'string',
      default: '',
      required: false,
    },
    SmallHero,
    seo,
  ],
}

export default page
Enter fullscreen mode Exit fullscreen mode

Keep Netlify CMS configuration DRY with partials

Every page file contains configuration for individual fields and uses partials to provide fields that are used across different collections/pages. The example above shows one section that is reused called SmallHero. The second most common partial we use is the seo partial. This partial provides metadata information for each page and collection item.

const seo = {
  label: 'SEO Settings',
  name: 'seo',
  widget: 'object',
  collapsed: true,
  fields: [
    {
      label: 'Title',
      name: 'title',
      widget: 'string',
      required: false,
    },
    {
      label: 'Meta Description',
      name: 'description',
      widget: 'text',
      required: false,
    },
    {
      label: 'Image',
      name: 'image',
      widget: 'image',
      required: true,
      default: '/img/shareable-default.jpg',
    },
  ],
}

export default seo
Enter fullscreen mode Exit fullscreen mode

With partials, you don't have to edit multiple files to make changes across collections or pages.

Complex data structures with Netlify CMS

I love ACF when working with WordPress. A lot of our projects since 2018 are made using Flexible Content from the Advanced Custom Fields plugin. It gives great flexibility for page creation for end users without the need for the developer's input. Headless CMSs started to adopt that feature, Prismic has Slices, Butter CMS has Components and Netlify CMS has lists.

For more on complex content solution read this article on recreating Flexible Content field with Netlify CMS & Gatsby

Lists support types params that can enable you to create flexible content fields. I wouldn't try that without manual initialization. That old YAML file would grow enormous quickly. Not to mention moving types across different pages.

import seo from '@/cms/partials/seo'

import SmallHero from '@/cms/partials/sections/SmallHero'
import DarkSection from '@/cms/partials/sections/DarkSection'
import Perks from '@/cms/partials/sections/Perks'
import Pointers from '@/cms/partials/sections/Pointers'
import Testimonials from '@/cms/partials/sections/Testimonials'

const collection = {
  name: 'services',
  label: 'Services',
  editor: {
    preview: false,
  },
  description: 'Service content',
  folder: 'content/services',
  slug: '{{slug}}',
  create: true,
  fields: [
    {
      label: 'Type',
      name: 'type',
      widget: 'hidden',
      default: 'service',
    },
    {
      label: 'Layout',
      name: 'layout',
      widget: 'hidden',
      default: 'Service',
    },
    {
      label: 'Title',
      name: 'title',
      widget: 'string',
      required: true,
    },
    {
      label: 'Featured Image',
      name: 'thumbnail',
      widget: 'image',
      required: false,
    },
    {
      label: 'Sections',
      name: 'sections',
      widget: 'list',
      types: [SmallHero, DarkSection, Perks, Pointers, Testimonials],
    },
    seo,
  ],
}

export default collection
Enter fullscreen mode Exit fullscreen mode

The example above showcases how I created service pages on Clean Commit's website.

Here's an example section - SmallHero

const smallHero = {
  label: 'Small Hero',
  name: 'hero',
  widget: 'object',
  collapsed: false,
  fields: [
    {
      label: 'Title',
      name: 'title',
      widget: 'string',
      required: false,
    },
    {
      label: 'Header',
      name: 'header',
      widget: 'string',
      required: false,
    },
    {
      label: 'Content',
      name: 'content',
      widget: 'markdown',
      required: false,
    },
  ],
}

export default smallHero
Enter fullscreen mode Exit fullscreen mode

Types with Manual Initialization is a perfect match for complex website content, making it possible to use Netlify CMS on both small and medium projects efficiently. Moving configuration between projects is also a breeze.

Key takeaways for keeping Netlify CMS configuration DRY

When your project gets large, use Manual Initialization instead of YAML configuration, it's easier to maintain.

Divide your Netlify CMS configuration into 3 base groups - pages, collections, and partials. Fields shared across different entities should become partials.

For flexibility in content creation combine manual initialization with Netlify CMS types using List widget. - For more on this topic read this article on recreating Flexible Content field with Netlify CMS & Gatsby

For more helpful tips check out the Tips & Tricks category on my blog

Top comments (0)