Hi there, here’s a short read about how I upgraded paulie.dev to Gatsby 5!
Now, I work at Gatsby but that’s not the reason I choose to upgrade using the following approach, I use the same approach whenever upgrading major versions as denoted by semantic versioning.
I Salute You Major Upgrade
The tricky thing with major version upgrades are, sometimes they’re backwards compatible, and sometimes they’re not. Naturally, the best way to determine what’s likely to cause a problem is to take the time to read about the changes.
The Gatsby Engineering team have put together a solid migration doc to help you on your way, you can read that here: Migrating from v4 to v5.
The only change to Gatsby that was likely to cause me a problem were the GraphQL schema changes to sort and aggregation fields but, thankfully there’s a codemod to handle this!
It’s also worth noting that, for now, Gatsby will automatically make the necessary changes to the affected GraphQL queries behind the scenes and show you a warning in the terminal. Support for this will, at some point, be removed so it’s best to address these changes sooner rather than later.
Besides the changes to the Gatsby framework, the key watch outs for my upgrade are that Gatsby 5 requires you also upgrade to:
- React 18
- Node 18
I could’ve “YOLO” upgraded both of these, but decided not to. Instead I, as mentioned, read about the changes, considered my options, and then set about performing the upgrades independently of one another, being sure to test everything still worked as expected before upgrading to Gatsby 5.
They did not, and here’s why.
The following error appeared after I upgraded to React 18 and deployed to Gatsby Cloud.
Error 425: Text content does not match server-rendered HTML
I only noticed it in the browser console after I’d deployed the changes because I was poking around for something else. It doesn’t appear locally when running either
gatsby develop or
It took me a little while to track this down and after much Googling around I found the root cause of the problem.
Date() constructor and the time difference, in seconds between server and client rendered HTML.
Here’s a post from my blog that explains the issue I experienced and a few ways to overcome it. React hydration error 425 “Text content does not match server-rendered HTML”
If you’re not already using Node 18 and attempt to install Gatsby 5 you should see the following warning in your terminal.
This happens because the Gatsby team has defined Node 18 in
You can see the
src for this file here: packages/gatsby/package.json.
This is all well and good, but there are a couple of things to consider before upgrading to Node 18. In my case I had concerns about some of the other projects I work on, and what problems I’d run into if I “YOLO” upgraded to Node 18.
Luckily there’s a way to incrementally adopt Node versions if you’re also in this situation.
Using Node Version Manager (nvm) it’s possible to set the Node version on a project-by-project basis… well kind of. You can use nvm to quickly set which version of Node should be used by a terminal “session”.
For instance when I’m working on a Gatsby 5 project, and I know it’ll require Node 18 I can run the following:
This will install the latest version of Node 18. If I close that terminal window however, and re-open the project, the default OS version of Node will be used, in my case that’s Node 16.
Whilst using nvm is a relatively good way to switch between Node versions it does require you to know which version of Node is required. If, like me, you work on a number of projects, it’s hard to remember which version to use. It’s worth noting too, not every node package defines the engines in
package.json, or warns when you have a mismatch!
Here’s the workflow I’m using to help catch errors and avoid burning time chasing down error messages.
Here’s how to get up and running with nvm: Installing and Updating nvm.
Once installed you can run the following in your terminal to create an
Depending on which version of Node you have installed on your OS will determine the output of the file. In my case the
.nvmrc file looked like this.
For Gatsby 5 projects, I need to change this to
With the correct version of Node set in the
.nvmrc file I can now run the following.
This will automatically install and use whichever version of Node is defined in the
This saves me from having to remember which version of Node is needed for any given project. It’s also worth noting that this approach is also super helpful when working on larger engineering teams as it’ll ensure consistency between individual local environments and depending on where you’re deploying, the production environments too.
The upshot should be slightly less of the classic “works on my machine” engineer response when things don’t work as expected.
As mentioned above, Gatsby already has this in
package.json, but for quick reference you could also add this to your project’s
The Actual Gatsby 5 Upgrade
Once I was happy with my Node workflow and had resolved the React 18 issues it was actually smooth sailing.
As mentioned, the only thing in my site that needed “changing” from a Gatsby perspective was the GraphQL schema which was quickly resolved by using the codemod. I would however like to point out one other change that you might not want to overlook.
Have a read of the release notes relating to the default setting for trailingSlash. This could impact your analytics.
Previously, in Gatsby 4, the default was “legacy”, this has now been removed and the new default is ”always”. This means any pages that were, E.g. paulie.dev/about would now become paulie.dev/about/. Notice the trailing slash after “about”.
This will trigger a new or different page view in analytics which might skew your reporting, so beware!
Is the Juice Worth the Squeeze?
You’ll no doubt be asking this question yourself, and whilst the actual upgrade to Gatsby 5 is pretty straight forward, in fact, dare I say, probably the best one yet, the surrounding upgrades to Node and React, as I’ve mentioned, can be a little problematic, but I think it is worth it.
My site, paulie.dev contains ~120 MDX pages with Code blocks, media embeds, webmetions and runs a number of large static queries to calculate metrics that I use on my /dashboard.
These large queries do have an impact on build times. I have however made use of Deferred Static Generation (DSG) for a number of pages and the dashboard is a hybrid SSG and SSR page. I went into more detail about how my site works in this post on Smashing Magazine: What’s New In Gatsby 2022?
For reference here’s the PR for my upgrade: https://github.com/PaulieScanlon/paulie-dev-2019/pull/85
And here are the results!
Clean cache and build Gatsby 4.24.4
- Local Build: 03:42
- Gatsby Cloud cold cache build: 04:05
Clean cache and build Gatsby 5.0.0
- Local Build: 2:53
- Gatsby Cloud cold cache build(s)
The mean average is around 2.5 minutes. The difference between Gatsby 4 and Gatsby 5 for my site, using Gatsby 5 is, ~47% faster builds!… and that’s without the Slice API!
Gatsby’s Slice API can help speed up build times when site-wide changes occur. A common implementation would be where you make a code or content change to something like your site header. The changes here would, historically have required Gatsby to rebuild every page that uses the site header… Not anymore. If your site header is a “Slice” Gatsby can intelligently rebuild the component and then “slot” it in amongst previously built HTML — I think that’s pretty neat!
I plan to write more about the Slice API soon but if you’re interested to know more, here’s a link to the Slice API Docs.
Lemme know how your upgrade goes!, and as always, you’ll find me on Twitter: @PaulieScanlon.