DevelopmentJune 7, 2026

Gatsby vs. Next.js for website development

At first glance, Gatsby and Next.js can look almost identical. Both are React-based frameworks, both do SSR and SSG, and both have huge communities. We use both technologies daily, but we believe each one fits different use cases best. We're often asked why we choose Gatsby over Next.js for website development, and in this article we explain it in detail.

When choosing the technology to build a website, there are several factors to consider:

  • Development speed
  • Editorial experience
  • Maintainability
  • Scalability
  • Customization

Here's what a feature comparison table between the two frameworks might look like. Almost identical, right?

However, those small differences can have a huge impact on website development.

Let's look at what a website needs and how each framework handles the same tasks.

Everything starts (or ends) with the favicon

It's a small, simple detail that every website has. But to cover the different use cases, operating systems, and browsers, you usually need more than one: 16x16, 32x32, 180x180, 512x512, etc. It's nice not to have to worry about it.

...and with Gatsby, you don't have to

You change a single line in gatsby-config.js and upload a favicon in png, jpg, or svg... and that's it. Gatsby generates the required icon set following best practices and optimizes the image without any extra work.

...but what about Next.js?

Next.js doesn't propose any specific way to do this. Search it on Google and you'll see how different the answers are; for example, this Stack Overflow thread. Everything has to be done by hand: optimizing the image, resizing it, and inserting the right tags with the <Head> tag. As an alternative, you can use favicon generators like this one.

The future is already here: image optimization

Both do a lot of magic: they process images with the sharp library and support modern formats like webp and avif, which translates into lighter files and a faster-loading website.

Both have their own image component, next-image and gatsby-image, with a similar API. But there are some differences.

Is next-image any good?

next-image is just a component: the actual optimization happens through an API route that receives parameters in the query string and returns the processed image, for example, /\_next/image?url=http://example.com/avatar.png&w=32&h=32

I like this architecture because it adds extra flexibility: you can use optimized images without needing a React component.

Another important detail: next-image forces you to specify the image's width and height, something you don't have when you get the data from a CMS, unless you use layout="fill"; but then you have to manage the image container's logic by hand. So, to avoid layout shifts, you have to fetch the image from the CMS, extract its width and height, and then, for example, use the CSS aspect-ratio property or resort to the SVG trick, as gatsby-image does automatically, to keep the original proportions.

Or is gatsby-image better?

gatsby-image doesn't have that API endpoint and works its magic behind the scenes thanks to its GraphQL data layer and various transformer plugins. Everything works out of the box, with no extra configuration. But there's something else Gatsby does better: art direction for images. Art direction consists of defining several srcsets for different screen sizes, with different crops and framing. A typical case is a large diagram, say on the homepage, that would look too small on mobile if you simply scaled it down. The solution is to pass an alternative image with larger diagram labels to the srcset optimized for mobile.

The importance of CMS integration

To offer the best experience to the client, it's very valuable to give editors maximum flexibility and to have solid CMS integration. On the websites we build, every word and every page can be edited from the CMS, just like any additional metadata: page URL, meta tags, og tags, etc. Most of the time we use headless WordPress, but sometimes we work with Contentful, Strapi, or Prismic, so having a flexible and simple way to fetch data from different platforms is essential.

Gatsby and the power of plugins

With Gatsby, integration is just a matter of installing a plugin and adding the API keys. There's no need to fight with SDKs or dig through API documentation. Everything is fetched and added to Gatsby's unified GraphQL layer. There are so many plugins that you'll find a source plugin for pretty much anything. Does the client use a recruitment platform and want to show job openings on their website too? No problem. Do they want to show a list of GitHub repositories with a star counter? Find the right plugin and you're done. The data gets added to GraphQL and you don't have to worry about the learning curve of each API.

Example of fetching data with GraphQL in Gatsby using the gatsby-source-wordpress plugin
Example of fetching data with GraphQL in Gatsby using the gatsby-source-wordpress plugin

Next.js's custom-built approach

Next.js doesn't have a plugin ecosystem, so to fetch data from a CMS you have to find the SDK, learn its API, figure out how to reuse that integration across different pages on the site, and probably build wrappers around the SDK for the most common cases, or some HOC. On small sites this might be manageable, but on large ones it forces you to spend time thinking about the overall data-fetching architecture and the scalability of the solution.

To preview or not to preview?

Okay, let's take a step back, because I'm sure a lot of people don't even consider offering this feature to editors. Previewing means rendering a specific page from the CMS on demand without publishing it to production.

If you use Gatsby, it supports the most popular CMSs and works seamlessly. You can use Gatsby Cloud, which automatically creates the preview server, so you just have to point the CMS to the right URL, or you can deploy a self-hosted version by running gatsby with GATSBY_ENABLE_REFRESH_ENDPOINT=true. Below is an example of how it works with Gatsby and headless WordPress.

With Next.js, once again, things get more complicated; check the official documentation. Again, you have to code it by hand for each entity you want to preview, defining how the data coming from the preview trigger is interpreted, what gets fetched next, and what gets rendered. Instead of Gatsby's five-minute setup, you'll have to invest hours to get something usable.

Flexibility for editors with programmatic page generation

Options in Next.js

To offer a top-tier editorial experience, editors need to be able to decide the URLs and the pages shown on them. Let's break the pattern and start with Next.js this time. There are several ways to achieve this, fully or partially.

  1. Hard-code the URLs of the dynamic subpages, e.g. pages/post/[slug].js. For example, the CMS has a slug field for each post and you agree it will always live under /post; then you define getStaticPaths in the component.

  2. Create a catch-all component at the root, pages/[...path].js, and then an additional wrapper component with the logic that maps each URL to a specific component. This creates quite a few problems and greatly increases the complexity of the architecture.

  3. Use Faust, a framework built on top of Next.js and specifically tailored to integrate with WordPress. If you look at the source code, you'll see it does exactly what option 2) does, and how complex that turns out to be. It also only works with WordPress.

The Gatsby way

Gatsby was born as an SSG framework, so it has some very powerful architectural concepts:

  1. A single point of programmatic page generation in gatsby-node.js. Imagine telling the framework in plain language: "Get all the pages from the CMS, create a Gatsby page for each one from a template, and make it accessible at the URL defined in the CMS." This way we can use different templates for each page based on the CMS data.

  2. The concept of templates. Separating pages from templates makes it easy to combine hard-coded URLs with pages created programmatically from templates.

The result is that you can create routes and pages fully controlled from the CMS without getting tangled up in complicated code logic.

We want Incremental Static Regeneration

Incremental Static Regeneration (ISR) allows you to update only certain pages incrementally, instead of rebuilding all of them every time changes come in. Technically, incremental builds aren't the same as ISR, but both try to solve the same problem: speeding up content updates in production by updating pages incrementally. Gatsby has had incremental builds since v3 and takes full advantage of them with various CMS integrations and Gatsby Cloud, rebuilding only what's new, which usually takes just a few seconds.

Next.js followed a somewhat different approach that didn't require triggering an additional build when something changed in the CMS. Instead, it let you specify how many seconds the page would be served from the cache; once that time passed, it would fetch the new data when the first unlucky user arrived.

At first I planned to include this as a downside of Next.js. It was a highly requested feature, but while writing this article, on-demand ISR was announced, which should solve the problem by allowing you to revalidate the cache through external calls. As of February 17th it's considered a beta feature.

Querying data anywhere

Another highly requested feature in Next.js is being able to query data, in the style of getServerSideProps or getStaticProps, at the component level and not just in the parent page. Right now you have to resort to props drilling or stores/context to pass data from the top level down to lower components. React 18 and Server Components should solve this problem in the future.

Meanwhile, in a Gatsby project you can fetch data from the global GraphQL layer from anywhere with useStaticQuery. This simplifies the architecture and lets you have reusable components.

Very external imports

This is a recent addition to Next.js and looks set to become a huge advantage when combining Low-Code/No-Code solutions with hand-coded applications. To understand this feature, the best thing to do is read this great example of using Framer together with Next.js. You can create a custom component in a visual editor, maybe add some flashy animation to it, and then import it into the project with a single line:

It's impressive and opens up a lot of possibilities. Gatsby doesn't support this yet, so if it's something you want to use in your project, Next.js is probably the better choice.

Sitemaps always help

Both frameworks solve this with additional libraries. Gatsby does it with a plugin and minimal configuration. In Next.js, a library does the same thing, but it requires running an extra script after the build.

Hassle-free i18n

The interesting thing about this point is that, even though the implementation is nearly identical in both frameworks, another Next.js feature called Global Middlewares makes it much more powerful. It lets you define a top-level middleware and, for example, detect the user's country at the edge and then serve them a statically generated page or redirect them to one.

Conclusion

We can keep recommending both frameworks for website development as highly reliable solutions. Even so, Gatsby clearly performs better for static generation and integrations thanks to its plugin ecosystem. For us, those features are critical, and we see how Gatsby lets us build websites faster while keeping them flexible and easy to maintain. Next.js is a framework more geared toward dynamic use cases, and I would only choose it if I needed an extra authentication layer on the site or that Global Middleware feature that helps with i18n, A/B testing, or feature flags. Those are very interesting features, but they're usually only needed on huge, enterprise-level projects, where that kind of experimentation is affordable.

Tell us about your case

Get in touch