Published on

Migrating From GatsbyJS V1 to V2


I have been using Gatsby for a couple of years now as the framework for my blog. Version 2 came out about a year ago but I've been procrastinating doing the upgrade. When I did try to migrate I tried to upgrade what I had using the official upgrade guide.

In my case trying to upgrade what I had using this guide was a mistake. I spend quite a chunk of time following this guide and kept running into issues. Eventually, I abandoned this approach and forgot about upgrading for a few months.

When I picked this up again I rethought my approach. Firstly I looked at what I had with v1:

  • A blog focused on the articles.
    • When I switched to Gatsby I intentionally went with a minimal spartan theme as I wanted the main focus of the blog to be about writing articles as often as possible not about playing with tech.
  • The use of Netlify instead of Digital Ocean to go fully serverless - I did not want to have to worry about keeping my Ghost droplet up to date (this again comes back to being able to focus exclusively on writing as many articles as possible).
  • I had made some enhancements to my setup over the last few years but mainly utility focused enhancements as opposed to aesthetic ones:
    • Setup Netlify CMS to allow me to write and edit articles anywhere.
    • Code syntax highlighting.
    • Publish flags in my markdown files to allow me to commit partially complete articles without having them published.
    • A plugin to allow me to write graphs in the mermaid syntax and have them render as images.

Upgrade Approach

Based on the assessment from the previous section, I realised trying to upgrade what I had was silly. Instead, my approach was:

  • See what v2 Gatsby Starters there are.
  • Pick the one that is as close to what I have as possible.
    • Ideally match what I have -feature wise- or beat that.
  • Make sure the vanilla starter works correctly.
  • Migrate my content to the new starter.
  • Update my markdown front matter to conform to what the new starter expects.
  • Fix any other issues encountered.
  • Install any additional plugins - if needed.

Choose a Starter

After browsing through the starters I settled on Lumen which perfectly matched these criteria.

I created an empty project against this starter and confirmed it ran without issues:

## Create a new blog with this starter
gatsby new blog

## start gatsby
cd blog
gatsby develop

I confirmed that the sample content worked correctly and was happy to proceed with the next step in the migration.

Create a New Branch on the Existing Blog Repo

This is important.

If something goes wrong with the upgrade you do not want to be forced to sift through commits to find where the issue is. You also do not want to affect your existing blog during this upgrade process.

If you are using Netlify then making changes against master will result in those changes being deployed by Netlify as it deploys changes to master by default. Having an upgrade branch prevents these upgrade changes deploying until you are ready to deploy them.

Move The New Starters Files Across

With the new branch created I:

  • Created a folder to hold my blog markdown files and specific config I need to keep track of (like my Google Analytics details).
  • I deleted everything else on the migration branch with the exception of:
    • The folder with my configs and blog markdown files.
    • The .git directory.
  • I copied everything from the vanilla starter from above.
  • I fired up the blog from this branch and confirmed the sample content was still rendering without issues.
  • Delete the sample articles
  • Move my existing articles into the starter's article folder.
  • On trying to start the app up again I ran into a bunch of issues due to Lumen expecting different front matter. In my case, I did not have this or the front matter I had was slightly different:
    • My publish flag became a draft flag on Lumen and I had to invert the value
  • This was as easy as doing a find replace on all post markdown files.
    • A description field had to be added.
    • A template field had to be added with the value "post"
    • A category field had to be added.

Adding these additional fields to about 300 markdown files seems like it would be tricky but I found a nice trick:

  • In a terminal cd to the directory with all the markdown files.
  • Open VS Code or whatever editor you use in that folder.
  • Do a blanket find replace where you find an existing front matter field in all posts and replace that with the field itself plus newlines and each additional field you need to add.
    • For example in my case I did a blanket find replace with RegEx turned on and I:
      • Searched for: (title:.*)
      • And Replaced this with: $1\ntopic: "Tech"\ndescription: ""

After this find-replace, the blog started up perfectly and I could view my content.

Update the config

Now that my content had been migrated successfully I needed to tweak the default config to my config. The Lumen project is exceptionally well organised and updating the config was simply a matter of updating the config.js file in the root of the project. I updated it with:

  • My Google analytics code.
  • My blogs title and description.
  • Me as the author.
  • My social media details.
  • Install the Mermaid remark plugin for the Mermaid graphs in my markdown.

I finalized the config update by creating a simple image with an 8 in to replace the default blog favicon and image.

Remove What You Don't want in the starter

There were some things I did not want in the default starter. I dug around a bit to understand how these pieces fit into the starter and removed what I did not want.

The Lumen starter comes with extensive tests. To make sure they still passed after my changes I ran yarn test -u to update the associated Jest artefacts (this process shows you the before and after so you can confirm updating makes sense). Finally, I confirmed that the tests still passed by running yarn test.

Configure Netlify CMS

This blog comes with the config for Netlify CMS in place. The only issue I had was that this config uses git-gateway as the backend for the CMS. In my case, this did not work as git-gateway uses Netlify Identity. Netlify Identity lets you log in with your Netlify credentials and use that to manipulate your blog. This is a really amazing feature if you have multiple people that access your blog as you can assign different access rights.

In my case I decided to not use Netlify Identity as I could not workout how to get it to work with oauth. It only seems to support straight forward username and password logins.

If you do want to use Netlify Identity you will get an error like Failed to load settings from /.netlify/identity when trying to login using it if you have not enabled it. This can be done as described here - basically login, go to the site you want to enable it for, click Settings > Identity > Git Gateway (at the very end of the settings page) > Activate.

My final config looked like my original one with additional collections added:

  name: gitlab
  repo: yourUserName/yourGatsbyRepoName
    create: Create {{collection}} "{{slug}}"
    update: Update {{collection}} "{{slug}}"
    delete: Delete {{collection}} "{{slug}}"
    uploadMedia: Upload "{{path}}"
    deleteMedia: Delete "{{path}}"

media_folder: 'static/media'
public_folder: '/media'

  - name: 'posts'
    label: 'Posts'
    folder: 'content/posts'
    create: true
    slug: '{{year}}-{{month}}-{{day}}-{{slug}}'
      - { label: 'Template', name: 'template', widget: 'hidden', default: 'post' }
      - { label: 'Title', name: 'title', widget: 'string' }
      - { label: 'Slug', name: 'slug', widget: 'string' }
      - { label: 'Draft', name: 'draft', widget: 'boolean', default: true }
      - { label: 'Publish Date', name: 'date', widget: 'datetime' }
      - { label: 'Description', name: 'description', widget: 'text' }
      - { label: 'Category', name: 'category', widget: 'string' }
      - { label: 'Body', name: 'body', widget: 'markdown' }
      - { label: 'Tags', name: 'tags', widget: 'list' }

  - name: 'pages'
    label: 'Pages'
    folder: 'content/pages'
    create: true
    slug: '{{slug}}'
      - { label: 'Template', name: 'template', widget: 'hidden', default: 'page' }
      - { label: 'Title', name: 'title', widget: 'string' }
      - { label: 'Slug', name: 'slug', widget: 'string' }
      - { label: 'Draft', name: 'draft', widget: 'boolean', default: true }
      - { label: 'Body', name: 'body', widget: 'markdown' }

Tag Master and Merge the Migration Branch In

Once I had done all of the above I was satisfied that I had completed the migration. The last step was to set the migration branch as master and have Netlify deploy these changes.

For sanity sake and to allow me to easily revert the changes I tagged the current master branch as v1:

git checkout master
git tag -a gatsby-V1 -m "Pre-migration to Gatsby v2"
git push origin gatsby-V1

I then switched over my migration branch to master, pushed and held my breath:

git checkout gatsby-v2-starter-lumen
git merge --strategy=ours --no-commit master
git checkout master
git merge gatsby-v2-starter-lumen
git push

I waited for a few minutes ... And my new migrated blog showed up perfectly fine!