Lachlan's avatar@lachlanjc/notebook

Why I switched from Gatsby to Next.js

Someone asked me why, after 1.5 years of using Gatsby for all my JS projects, I switched to Next.js. Here’s how I’m thinking about it, & why I use Next.js over Gatsby for everything new.

Advantages of Gatsby over Next for static sites:

  • Plugins. If you want to add something like styled-components, you just install one package, add one line to your config file, & all your configuration is done. With Next, libraries like styled-components require adding custom hooks/components/etc to your_app & _document files.
  • Data sources. If you have structured data coming in from a CMS like WordPress, there’s Gatsby plugins that make fetching that data much easier. The way you consume this data is then via their GraphQL engine, which personally I find overwhelmingly too much & confusing & convoluted for the majority of relatively small-scale projects. However, with Next you have to do all data fetching yourself.
  • Themes/recipes. These are very in-development, they’re poised to make building Gatsby sites way easier, but they are not nearly well-documented enough or popular enough yet to rely on. I’ve been writing static JS/React sites for 5 years & I find them utterly baffling when I have used them in the past, but I’m optimistic they’ll get better over time. Next, meanwhile, has no analogy to these.

One obvious deal-breaking limitation of Gatsby vs Next is that Gatsby only builds static sites, whereas Next is hybrid, so it can make a fully static site, a partly static & partly dynamic site (different pages are each), or entirely dynamic.

Dynamic features of Next: (which Gatsby does none of)

  • API Routes. You make endpoints in pages/api, which are serverless functions that run dynamically.
  • getServerSideProps. Pages can be server-rendered on-demand, fetching the latest or custom user data.
  • getStaticProps. This is the most brilliant part of Next, & the feature Scrapbook’s site runs on, as well as tons of other Hack Club sites. Essentially, on build the page will run a function to prepare props that are passed to the page. I find this so, so, so much easier than using a component or Hooks to write a GraphQL query to get stuff out of Gatsby, & it’s way more flexible. Going alongside this, you can give getStaticProps a revalidate option, which means if it’s been that number of seconds since the page was last loaded, it should re-run the getStaticProps function to regenerate the page—in the meantime, it’s still serving the static page from cache, but then hot-updates that single page so future loads get the new data. This is a serverless operation that happens basically instantly, silently, & makes individual pages always up-to-date with new data without re-building the entire site for one bit of functionality. I explain how Scrapbook uses it alongside Vercel’s SWR library here.
  • (Not at all recommended anymore) Custom server. You can run Next from inside a custom Node server, though you lose all its hybrid advantages this way. (For dumb project timeline reasons, the Scrappy backend works this way! It’s wild.)

Making a static site with Next.js is super possible, & I find in most cases, simpler than doing the same with Gatsby. If you’re looking to use Gatsby for its data source features, go for it, & if you want a dynamic backend, I highly recommend deploying on Vercel (or Netlify) to use the serverless functions those platforms offer, which with a bit of configuration can replace Next’s API routes. Everything that Next does you can run on any Node server hosting, but Vercel seamlessly, perfectly detects dozens of things & optimizes them (hosting static files on a CDN, including pushing getStaticProps-updated pages to the CDN) so you get the fastest hosting & deployment out of the box.

Personally, I’ve given up on Gatsby/way prefer Next.js:

  • Plugins are handy, but don’t do anything I can’t typically paste into my Next project, meanwhile lots of them balloon build times with hidden processes that are impossible to customize or debug.
  • The slowness of the development server, plus its unreliability (I find myself needing to restart the server & gatsby clean many times a day working on Gatsby sites), drove me bananas, whereas Next.js is the only framework implementing Fast Refresh, the (near-perfect, in my experience) system for hot-swapping React components in-place while preserving state, & it’s leagues faster.
  • The build times on Gatsby I find end up 3x my Next sites, even though the Next build process is doing so much more. I don’t want to get into the politics of the company too much, but it feels like a lot of Gatsby is built on hacks on top of bad code/infrastructure the founder wrote years ago.
  • The management/direction of the company (the Cloud hosting they’re trying to sell to make up for the terrible build times, the management’s public missteps, the raising of boatloads of VC instead of focusing on great DX) don’t make me optimistic for the future of the company.
  • The framework itself seems to not be innovating anymore—their latest feature is trying to port the original great idea of Next’s router into Gatsby, which is too little too late to me. Every Next release pleasantly surprises me with a mix of features I didn’t know I needed & solid iterations. The team is super responsive to feedback.
  • I dislike how hard it is to start a Gatsby project yourself—whereas with Next, the API surface area to remember is tiny, & a new project involves only creating a pages directory with a JS file, & downloading next react react-dom. With Gatsby, you need to download a bunch of packages realistically, remember a bunch of custom files with different formats, & basically always copy & paste a ton of things.
  • I love how Next automatically handles polyfilling fetch both client & server-side, supports the latest Babel goodies, TypeScript, & other little things Gatsby doesn’t do seamlessly out of the box.

One site we used to have on Gatsby I rewrote with Next is our site. In the Gatsby days, the Gatsby configuration file made a download of JSON from a server, put it in the filesystem, then used a JSON filesystem plugin to read that into Gatsby’s GraphQL. The homepage then queried the GraphQL & rendered the components. In that config file, we also queried the years the events were in, looped through them, then rendered a year page template for each, & that page then queried all the hackathons filtering by the year provided by the template rendering. When data changed on our API, we used a background job to re-deploy the site on Netlify, so it took a few minutes to go live.

After rewriting that site with Next (which took me about an hour, with design, for the MVP), the system is so much simpler: I made a collection of functions using fetch to download hackathons from Airtable (using airbridge). The homepage uses getStaticProps revalildating every few seconds, so there’s a JS array available as a prop to render components from. The year pages, which require no outside configuration, use getStaticPaths to render for each year, fetch the same hackathons & filter them in one line of code in getStaticProps, & update themselves on-the-fly. This is a fraction of the complexity, while also having near-instant updates & still having a static site with client-side functionality. Since those functions were ready, I made an API in like 20 minutes two months ago for the site, so anyone can use our data. I wrote about the general idea of this implementation in a proposal to do this for all Hack Club projects last winter.

If plugins/data sources make your architecture way easier, go for it. But beyond that, I find everything about Next.js vastly preferable, & they’re iterating way faster.