Deep Dive

Our Failed Migration To Netlify CMS: Post Mortem & Lessons Learned

Published by

Junior Felix

featured image Our Failed Migration To Netlify CMS: Post Mortem & Lessons Learned

When we redesigned our website, we wanted to create a solution that would allow us to focus on creating content rather than managing the infrastructure. To achieve this, we decided to replace our existing content management system (CMS) with Netlify CMS (now known as Decap CMS), which is a git-based CMS that does not require us to manage the API infrastructure. However, this decision brought several challenges, and we ultimately decided to remove Netlify CMS from our website’s architecture.

In this article, we will discuss the migration process, the challenges we faced, and our decision to roll back away from Netlify CMS.

💡 Despite the rebranding to Decap CMS, we will continue to refer to the CMS as Netlify CMS for clarity since that was the name it had when we were working with it. More information on this change can be found here.

Where We Started

Initially, our company website had the following technology and infrastructure:

Untitled(5).png

Our infrastructure was as follows:

Why We Wanted To Migrate

Three main reasons inspired the desire to migrate from the above architecture:

To Bring Down Infrastructure Costs

The existing setup did not require a lot of money, but we could still lower costs by changing the design. Since our website does not change much in a short time, the current design was too complicated for our mostly static content.

Plus, the original architecture had multiple parts that cost money: database, headless CMS, front-end, and file storage.

To Improve The Development Experience

Initially, the local setup was using data from the deployed infrastructure. This structure led to an unclear separation between the production environment and the development environment. Consequently, dependency issues arose during the development process; such as the setup not working when internet was unavailable locally.

Although it was technically feasible to set up a multi-environment Strapi CMS deployment that would meet all of our requirements, we decided against it as it would have added further complexity to our development process, which seemed counterintuitive.

To Simplify Our Architecture

Our initial setup had a three-tier architecture, which can be a lot for a company website. Consequently, we were motivated to move towards a simpler architecture. Eventually, we settled on migrating to a JAMstack architecture.

The JAMstack architecture leverages Javascript, APIs and Markup to create fast and secure websites in the following way:

  • Javascript: Handles the dynamic features of the application. This can be vanilla Javascript or a Javascript framework. It is important to note that Javascript runs entirely on the client.
  • APIs: Handles server-side operations by abstracting them into reusable APIs that are accessed by the client via HTTPS. These APIs can be 3rd party services such as Auth0 or custom-built serverless functions.
  • Markup: Refers to HTML, CSS and other static assets that make up the frontend. In applications that involve dynamic content, static site generators such as Gatsby are used to pre-render the markup and serve it to a Content Delivery Network (CDN), which can be accessed by clients.

The following diagram illustrates our implementation of the JAMstack architecture:

JAMstack Architecture.png

The above setup had the following major components:

  • Gatsby: serves as the static site generator that compiles the web application into static HTML, CSS and JavaScript that can be served to visitors.
  • Netlify: functions as the Content Delivery Network(CDN) that serves static files to users.
  • Netlify CMS: allows the users to manage the website’s content. Since it is a git-based CMS, once the user makes changes, those changes are saved to a git repository. Once the git repository is updated, Netlify rebuilds the site and deploys the updated static files.
  • Serveless functions: handles the dynamic functionalities of our website such as form submissions.

The Migration Process

During the migration process, we had the following objectives:

  • Transform data from the website's database into Markdown files.
  • Move Markdown files created and static files (e.g. images) to the website's GitHub repository.
  • Integrate Netlify CMS into our Gatsby front end.
  • Successfully deploy the new setup.

These goals were achieved through the following steps:

Data Migration

In this step, we had to transform our content data into a form that can be represented in markdown files.

For instance, our MongoDB database returned articles’ documents as follows:

1[
2  {
3    "_id": { "$oid": "638a0438fc13ae38050000bc" },
4    "title": "First Article",
5    "category": "Balanced Analysis",
6    "published": "12/25/2021",
7    "author": {
8      "name": "John Doe",
9      "title": "Software Developer",
10      "link": "https://johndoe.com"
11    },
12    "body": "Nulla mollis molestie lorem. Quisque ut erat. Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem. Integer tincidunt ante vel ipsum. Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat. Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede. Morbi porttitor lorem id ligula. Suspendisse ornare consequat lectus. In est risus, auctor sed, tristique in, tempus sit amet, sem. Fusce consequat. Nulla nisl. Nunc nisl. Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum. In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo. Aliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis. Sed ante. Vivamus tortor. Duis mattis egestas metus. Aenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh. Quisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros. Vestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat. In congue. Etiam justo. Etiam pretium iaculis justo. In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus. Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi. Cras non velit nec nisi vulputate nonummy. Maecenas tincidunt lacus at velit. Vivamus vel nulla eget eros elementum pellentesque. Quisque porta volutpat erat. Quisque erat eros, viverra eget, congue eget, semper rutrum, nulla. Nunc purus. Phasellus in felis. Donec semper sapien a libero. Nam dui. Proin leo odio, porttitor id, consequat in, consequat ut, nulla."
13  }
14]

Creating a markdown file for this article would result in:

1---
2title: First Article
3category: Balanced Analysis
4published: 25-12-2021
5author:
6  name: John Doe
7  title: Software Developer
8  link: https://johndoe.com
9---
10
11Nulla mollis molestie lorem. Quisque ut erat. Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem. Integer tincidunt ante vel ipsum. Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat. Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede. Morbi porttitor lorem id ligula. Suspendisse ornare consequat lectus. In est risus, auctor sed, tristique in, tempus sit amet, sem. Fusce consequat. Nulla nisl. Nunc nisl. Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum. In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo. Aliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis. Sed ante. Vivamus tortor. Duis mattis egestas metus. Aenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh. Quisque id justo sit amet sapien dignissim vestibulum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est. Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros. Vestibulum ac est lacinia nisi venenatis tristique. Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue. Aliquam erat volutpat. In congue. Etiam justo. Etiam pretium iaculis justo. In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus. Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi. Cras non velit nec nisi vulputate nonummy. Maecenas tincidunt lacus at velit. Vivamus vel nulla eget eros elementum pellentesque. Quisque porta volutpat erat. Quisque erat eros, viverra eget, congue eget, semper rutrum, nulla. Nunc purus. Phasellus in felis. Donec semper sapien a libero. Nam dui. Proin leo odio, porttitor id, consequat in, consequat ut, nulla.

The set of key/value pairs at the beginning of the markdown file provide more information of the article itself. This data is referred to as frontmatter; which is useful when performing queries at the GraphQL data layer. The actual body of the article follows the frontmatter section.

Afterwards, we moved the markdown files into the GitHub repository, depending on the content type. For instance, blog posts were moved into

1netlify/blog
.

Netlify CMS Configuration

In this step, we laid the foundation for Netlify CMS use in our application. This process entailed:

  • Adding the necessary NPM packages: Netlify CMS npm package and Gatsby Netlify CMS plugin
  • Creating the required folder structure and adding the
    1config.yml
    file to handle Netlify CMS configuration settings.
  • Adding settings for the content data that will be edited using Netlify CMS.

For the content type settings, we derived standard properties from the data we obtained from our database. For example, for our blog posts, we concluded that the following properties are standard:

  • Title
  • Category
  • Author
  • Publication Date
  • Body

Therefore, the blog section of our

1config.yml
file was as follows:

1collections:
2  - name: "blog"
3    label: "Blog"
4    folder: "netlify/blog"
5    create: true
6    fields:
7      - { label: "Title", name: "title", widget: "string" }
8      - {
9          label: "Category",
10          name: "category",
11          widget: "select",
12          options:
13            [
14              "Tutorial",
15              "Architecture Breakdowns",
16              "Balanced Analysis",
17              "Deep Dive",
18            ],
19        }
20      - label: "Author"
21        name: "author"
22        widget: "object"
23        fields:
24          [
25            { label: "Author Name", name: "name", widget: "string" },
26            { label: "Author Title", name: "title", widget: "string" },
27            { label: "Author Link", name: "link", widget: "string" },
28          ]
29      - { label: "Publication Date", name: "date", widget: "date" }
30      - { label: "Body", name: "body", widget: "markdown" }

In this section, we specified the property and its corresponding widget to edit it. More information on the

1config.yml
can be viewed in the Netlify CMS docs here.

Deployment Of The New Setup

Since we were hosting our website on Netlify CMS, our changes were continuously deployed when we were making commits and merging with our main branch. Considering that the new setup was git-based and used markdown files, the changes we implemented were reflected in real-time.

However, since we chose to use Netlify's built-in authentication service for the CMS, we had to do additional configuration. The steps we followed can be found here.

The Catch

Despite the attractive promises of JAMStack and Netlify CMS, the reality fell short of expectations. In the migration process, we encountered difficulties that snowballed into larger obstacles.

Tedious Migration Process

During our migration process, we had to convert each content type data into markdown files, which was tedious. Since this was the first iteration of our content in markdown, the shape of our data was constantly evolving as we tried to find what worked.

For example, for our blog articles, if we wanted to introduce a “Last Edited” property, we would first have to edit the

1config.yml
file, then proceed to the individual markdown files and add the relevant data to each blog article markdown file.

Possible Workaround

Regarding this issue, our only option at the time was to manually edit the files.

The community has discussed creating a package that reads migration files and applies the changes to

1config.yml
. This package would also ensure existing data follows the new changes. For more information, see this open issue.

Complex Configuration Management

Netlify CMS sits in an awkward spot between providers like Contentful and more customizable solutions like Strapi CMS or custom-built content management systems. It relies on YAML-based configurations with limited options, combining the drawbacks of both. Additionally, at the time, Netlify CMS was not flexible enough to build a framework which would make configuration easier. Some of the challenges we experienced during configuration were as follows:

  • YAML is complex for non-technical users: Editing a YAML file may prove intimidating to website users who are not familiar with its syntax. As a result, activities such as creating new content types were limited to technical users, thus increasing the time consumed in development.
  • Difficulty in monitoring indentation: During development, the setup sometimes failed due to indentation issues. Keeping track of indentation levels of each line in the
    1config.yml
    file proved to be quite challenging.
  • Growth in complexity of the YAML file: As the content types got more complex, the
    1config.yml
    file got longer. This made it harder to maintain. Additionally, the lack of YAML schema made it more challenging to validate the contents of the config file.

Possible Workaround

At the time, there was no official implementation of a UI that edits Netlify CMS settings. However, community projects such as this exist to meet this need.

No Clear Division between Development and Production

As we had mentioned previously, one of the goals that we wanted to achieve is to help our engineers work more productively on a day-to-day basis by making sure they had an independent sandbox they could work from without external dependencies or similar limitations.

In the Netlify CMS setup, the development and production environment are closely coupled. By default, changes made either locally or on the published site fetch and commit files in the remote repository, as specified here. Consequently, it is difficult to separate changes made locally and the modifications made in production.

Since we wanted a better local development experience, Netlify CMS came up short in this regard. However, we tried some countermeasures to curb this issue.

Possible Workaround

To deal with this issue, we followed the doc’s recommendation to run a proxy server in the local environment and configure Netlify CMS to use it in the local development environment. The latter would allow us to change the content locally without interfering with the hosted repository.

This approach had its drawbacks. Firstly, it was in beta, so it could occasionally crash and publish to the remote repository. Secondly, Editorial Workflow couldn't be enabled. Without this feature, we had much less control over the publishing process. We couldn't save drafts or require an approval stage before publishing to production.

Dependency Issues

Since Netlify CMS is a self-contained React app, it brings about its share of dependency issues when updates are made to the packages it uses. In our case, updating React versions in Gatsby brought about build failures and installation errors in Netlify CMS. The open issues section of the repository reveals that this issue is prevalent and recurring whenever there is a new version of React.

Furthermore, the close coupling between Netlify CMS and the Gatsby-built website had led to a lack of clear separation between the two, and any errors in Netlify CMS builds would cause the website build to fail.

Possible Workaround

Running

1npm install —legacy-peer-deps
in the installation process allows us to ignore the dependency issues that arise. However, this countermeasure has a downside. Overlooking dependency issues can lead to breaking changes in our application.

Reflections and Future

Prior to choosing Netlify CMS, we conducted a thorough investigation of the various CMS options available. At the time, Netlify CMS had a high number of stars on Github and was frequently mentioned in technical blogs as a top choice for a headless CMS. However, in the exploration phase, we missed the following red flags:

  • Lack of new features: Even though Netlify CMS had a high number of stars on Github, it has not released new features to enhance the developer/user experience. In addition, the absence of a clear roadmap suggests that the overall direction of the project is unclear.
  • Poor maintenance: In addition to the outdated dependencies mentioned earlier, there were other signs that Netlify CMS was not being well-maintained. First, the project had a lack of community engagement. Responses to questions raised in Github discussions were slow and pull requests took a long time to be reviewed. Additionally, the project had a high number of open issues, with many of them being several years old. This frustration can be viewed on this netlify discussion forum discussion.
  • Beta features do not progress beyond the beta phase: Despite the introduction of beta features to Netlify CMS, little to no progress has been made in the development of these features. For example, the local development feature was introduced in early 2020, as shown in here, but has not progressed significantly since then.

Considering that Netlify CMS (now known as Decap CMS) has transitioned to new stewardship, it is worthwhile to observe whether this change will have a positive impact on its future trajectory.

Lessons Learnt

One of the key things we learned from this experience was the importance of being more careful when selecting an open source solution. Although Netlify CMS appeared to be a good fit initially, it ultimately did not meet our objectives.

Currently, we use Markdown files as our data source and make edits directly to them. We are still investigating other CMS options that might better suit our needs.

icon_emailaddress

Get our latest software insights to your inbox

More insights you might be interested in

Are Certifications Worth It?

Balanced Analysis

Are Certifications Worth It?

Explore various perspectives surrounding the controversial issue of the value of certificates in the tech community. Get an in-depth rundown of the pitfalls that arise from the use of professional certificates and how to use certificates optimally.

Why Containerize Your Gatsby Application?

Tutorial

Why Containerize Your Gatsby Application?

Learn why you should containerize you gatsby application using docker and how to do so with easy to follow steps regardless of the Operating System you are using.

Building Scalable Styling Architecture in React

Architecture Breakdowns

Building Scalable Styling Architecture in React

Explore the principles that create scalable styling architecture in react and learn practices that can achieve this desired architecture.

Seeding Data Into MongoDB Using Docker

Tutorial

Seeding Data Into MongoDB Using Docker

Learn how to seed data into MongoDB using docker and docker compose and use the generated data in a React application, through step-by-step instructions.