Published on

Migrating from Gatsby to Nextjs

Authors

Its been a while since I last blogged, this is largely due to being super busy but one of the other reasons is what lead to this migration. This post itself took some time to write up (hence why it is the second post since this migration).

This post gets into the why as well as how I migrated from Gatsby to Nextjs, what the major challenges were as well as what I lost and gained by moving across.

Why

Deciding on Ghost + Digital Ocean

When I first started blogging a few years ago, at the time my main motivations for it were that I wanted to build an online precense. In planning for that I ended up with Ghost for a few reasons:

  1. Timewise I wanted to focus on blogging and was not really interested in the look and feel.
  2. Cost wise I wanted to spend minimal to nothing on it every month.
  3. I wanted flexibility over the way content was rendered.
  4. I was not interested in worrying too much about infrastructure.
  5. I wanted something I could get up and running with minimal fuss.

So my options at the time were really Wordpress, Ghost and Medium or a similar platform.

Medium would have been good but I wanted more control and I wanted to use a custom domain and basically not be beholden to any gatekeepers.

Ghost + the Digital Ocean free tier ticked basically all those boxes. I have to pay annually to renew the domain name but otherwise cost wise it was as low as possible

Deciding to move to Gatsby + Netlify

Time went by and eventually I was frustrated by Ghost for a few reasons:

  1. I had to keep worrying about the infrastructure and upgrading it to deal with any security issues.
  2. I ran into difficulties with customizing the look and feel of Ghost - for example if I wanted to tweak the code syntax highlighting.
  3. I did not like that content was stored in a DB and not as raw markdown which resulted in more overhead if I wanted to worry about backing up the blog properly.

These factors and a talk at a conference about static site generators and in particular Hugo and Netlify lead me to Gatsby.

Gatsby ticked all my boxes and combining this with Netlify I ended up with a solution that required minimal server management (more on this in a bit) as it was statically generated. I discuss the process involved in migrating from Ghost to Gatbsy here

Deiciding to move to Nextjs + Vercel

A lot more time went by and I was very happy with Gatsby. Once I had it working I could just focus on blogging and not worry at all about infrastructure. I also had a pretty sweet setup with Gatsby to handle the static generation of the content, Netlify CMS as my serverless CMS and Netlify itself to handle serving of the statically generated content (for free on their hobby tier).

All was good until one day I received an email from Netlify notifying me that I needed to upgrade to a newer version of Ubuntu for the build container. This is the container that Netlify uses behind the scenes to run the node commands to generate your static site everytime you push.

I thought Ok awesome I simply need to go and change to a newer version of Ubuntu. So I nipped over to Netlify (the first time in ages as generally I did not need to do anything there), I switched to the latest Ubuntu LTS and I thought I was done. I forgot about it but then when looking through my emails I saw an email from Netlify notifying me how the build had ran but had failed for a tonne of reasons.

In these scenarios I normally timebox trying to fix the issue otherwise if I cannot get it working I use it as an excuse to bump to the latest version of what I am using. In this case I tried to fix the issues but to no evail. So I started investigating what was involved in migrating to the newest Gatsby.

I saw that there was a new major version since I'd set it up a few years back. After a bit of investigation I saw that Gatsby did not seem to be the way to go nowadays. This is purely subjective but these are the reasons I decided to shy away from it:

  1. Moving to Gatsby 4 required significant effort from what I could see:
    1. Most of the plugins I used (many of which were fairly popular) did not seem to be on v4 and I was not willing to test it in production (as mentioned before I wanted my main focus for the blogging platform to be on blogging and not managing infrastructure/dependencies etc.).
    2. There were breaking changes in the way new things work.
  2. The fact that many plugins I used did not seem to be migrating to v4, indicated to me that people have moved onto other platforms.
  3. For work I use Nextjs and I am very happy with it - I also like that they generally do not seem to introduce major breaking changes between releases.
  4. Most of the features of Gatsby I either did not really use/need or other frameworks provided:
    1. Exposing your data as GraphQL - I did not really need/use this for my use cases - despite it being a really cool feature.
    2. Statically generate content - there are oodles of frameworks that do this.
  5. My build times were steadily getting longer with each new article I added (as of this post I am sitting on about 400 articles). I could see this eventually being something I would have to fix as Netlify or/and Gitlab pipelines started to timeout.
  6. There seemed to be good competitors (in the JS space).

All these above factors lead me to Nextjs. A huge part of the decision to move across was that:

  1. I use it for work.
  2. They genrally seem to not introduce huge major breaking changes between releases.
  3. Vercel is constantly making new changes to it, changes I can see value in (for example speeding up build times signifcantly).
  4. I love that I can npm build and see if stuff breaks (more on this later, this was instrumental in helping me migrate as smoothly and quickly as possible).
  5. There is an enormous ecosystem around it.
  6. I can generally use normal React npm modules and don't need special framework modules.
  7. I like that I can start dipping into other ways of rendering should I choose to.
  8. As Vercel created and maintains it I imagined that the experience of using Vercel to host/build it would be optimal and I have always wanted to give Vercel a spin.
    1. I would also not likely run into the Netlify issue of having to worry about a broken build when upgrading (at least not anytime soon).
    2. Vercel does not seem to expose the container or similar backing container the way Netlify does which for my use case was perfect.
  9. Bare metal Nextjs out of the box has a ridiculously lite node_modules folder (less than 100MB as of the writing of this post 🤯).

How

Now that I had decided on what framework to move to, I embarked on looking for a good starter project to fork.

I eventually came upon this one.

I chose this as:

  1. It has a really well polished look and feel.
  2. It has been updated recently and is fairly active.
  3. There are no major issues open or that have been resolved.
    1. Even if there were, one of the major draws of a JAMStack is that the statically generated pages pose a really small attack surface.
  4. It's lighthouse score is almost perfect (the main gap is the progressive web app portion which should be easy enough to sort out).
  5. The base template is really solid and looks easy to build on top of.
  6. It uses TailwindCSS which Ive been wanting to play with for a while now.

I created a new branch on my existing Gatsby git repo and proceeded to start migrating.

Major Challenges

I started by copy pasting my raw blog markdown files across and then my images and other media. So far, so good 👌. This is where it started to get a bit tricky.

I ran an npm build and crossed my fingers 🤞. But as expected I am not that lucky.

Fortunately, the logs from Nextjs's build command genrally steered me in the right direction. I say generally as the files it errored out on were correct but the line numbers were way off.

I triaged the issues by going after the ones that appeared the most often. It turns out that this approach worked well as many errors in the error list were symptoms of other errors and not true errors.

My initial set of issues were caused by the way the front matter on the new framework was structured. I lazily used a blanket regex find replace to sort out most of these issues.

The next bunch of errors that stood out were related to something with the tag rendering as I kept getting a nonsensical error from Next about page path clashes. I tracked down the source of these by making the blog page renderer (the js file that converts the MD file into html files) log out the tags. This helped me pin point an empty - or two being used in the tag list which was causing an error about the same path being used by Nextjs. The issue seemed to be due to tags being trimmed and a and being trimmed down to the same empty space tag name. I nuked these tags as they were not meant to be there anyway and that chunk of issues was sorted.

The last major batch of issues I ran into was due to the new framework rendering all MD and MDX files using an MDX renderer plugin. MD files were also rendered as if they were MDX files. While this could be tweaked, I like the idea of being able to use MDX in MD where needed. My issue was caused by my use of tags in some articles. With vanilla markdown rendering this wasn't an issue but with MDX this does become problematic. I escaped these special characters and yet more issues melted away. Side note: to tell mdx to render an html tag as a string simply use a / after the tag's closing > so in the above I use @/> at the end of illustrative to tell mdx to not treat it as a tag, see here for a bunch of other options.

After a bit more whackamole I finally fixed all the errors and had my entire blog building and rendering smoothly (and nice and fast thanks to Nextjs's build performance improvements).

The last few touches I made were to:

  1. Change the author details.
  2. Tweak/remove social media links as needed.
  3. Configure Google analytics (there was some cross site cors header you need to add).
  4. Configure disqus (this still isn't working fully but a problem for another day).
  5. Adjust any other configuration.

Despite the last few little issues, I was finally comfortable to merge this branch into the main branch and get this moved over to Vercel.

Moving it to Vercel was trivial. I stood it up on Vercel, updated my DNS and finally I switched it off on the Netlify side.

What I gained by migrating

I gained a much more modern framework that comes with tonnes of batteries included. I also like that Nextjs does not seem to introduce any major breaking changes with major releases but keeps pushing the enevolope in terms of what their framework can do.

What I lost by migrating

I lost:

  1. The Graphql interface to consume data.
  2. The headless CMS using Netlify CMS:
    1. I likely can get this working on my new setup.
    2. I didn't end up using it all too much anyway.
  3. MermaidJS rendering:
    1. I figured this is fairly easy to sort out later with MDX and a plugin or custom component.
    2. I don't use this in too many articles.
    3. The raw MermaidJS is still fairly readable.

Some things I still want to do

I want to play around with Tailwind and build on top of the foundation I have to sharpen my CSS skills a bit.

I want to get Mermaidjs working.

I want to try out some lambda functions. A simple contact us page could be a good place to start. Vercel and many other platforms offer very generous free tiers for this.

I want to add a project's page for pet projects.

I want to try make the page a PWA.

I want to get the build process to auto publish to social media and cross post on other platforms like dev.to (seemingly simple but need to work out a way to avoid duplicates for example if the build reruns for whatever reason).

I've toyed with the idea of migrating this Nextjs template to Typescript but:

  • I don't really see much value in this for my case.
  • The build command does its job and I mostly have simple blog pages.
  • I want to be be to copy paste upgrades to the template easily.
  • I could end up using Typescript for a few custom components I have but use Javascript everywhere else
    • A really nice feature of Typescript - it does not force you to big bang migrate.