Gatsby to Next.js migration

By Pieti Kinnunen

January 22nd, 2025

Migrating from Gatsby to Next.js can be a great choice for modernizing your website and making your website better fit your needs. Both frameworks are based on React, so many of your existing components should migrate quite easily. However, there are significant differences in routing, data fetching, and static asset handling that you’ll need to address. Here’s a guide to help you make the transition simple.

    Table of contents

  • In this post:

Getting Started

Next.js has two approaches for their routing: Pages Router and App Router. For this migration, I would go with the newer App Router over the previous pages router, as it is the recommended way of structuring Next.js applications and the Next.js team will likely offer support for it longer than the older Pages Router. You’ll also be able to leverage the newest React features, such as server components, with the App router.

To begin, you can either create a new Next.js project or update your existing code to use Next.js instead of Gatsby. I’ll briefly go over both setup methods

Creating a new project

You can create a new Next.js project either by using the npx create-next-app@latest -command, which guides you through options for your project and sets up boilerplate files.

The other method would be to create the project and files manually from scratch is to use npm install next@latest react@latest react-dom@latest to install the required dependencies. After this you should update the scripts section in package.json to look like:

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
}

After this you'll need to create the needed files yourself, for example the app directory and config files.


Updating your existing code


Alternatively, if you want to reuse the existing directory of your Gatsby project you'll need to pretty much do the same steps as with manually creating a new Next.js project:

  1. Remove all Gatsby dependencies from your package.json.

  2. Update the scripts section in package.json to look like:

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
}
  1. Install Next.js and its required dependencies using:

npm install next@latest react@latest react-dom@latest

After these steps you can move on to the next steps

Creating Routes

Both Gatsby and Next.js use file-system routing, which means the routes in your application are determined by how you structure your files, eg. src/pages/page-slug/index.js in Gatsby can be accessed at www.your-site.com/page-slug and the same address in Next.js would be the file src/app/page-slug/index.page.js.

Moving your static pages over from Gatsby is simple; you should be able to just move them into the Next.js app directory.

Dynamic Routes: In Gatsby, dynamic routes are created using the createPages API, whereas in Next.js, you define them directly in the file name using square brackets.
For example: Next.js: src/app/[slug]/page.js.

To fetch the slugs that'll be used for creating these routes, implement the generateStaticParams function in your dynamic route file. For example:

export async function generateStaticParams() {
const slugs = await fetchSlugs();
return slugs.map((slug) => ({ slug: slug }));
}

With this function you can get the slugs from wherever you need, eg. create them from markdown files in your codebase or fetch them from a CMS. The word "slug" in the directory name can be replaced with any word, you'll just need to make sure your generateStaticParams returns an array of objects with a key of the same name.

Creating Pages

In Next you can create a layout.tsx file in the root of the app directory to include data or components on all pages that are included in that directory. In the layout you should include shared meta tags, scripts and for example your header and footer. Similar layout wrappers can be created on lower directories as well if you want to have some shared data only on specific routes.

Internal routing

You need to convert your Gatsby internal link components to use Next's Link component. There isn’t much difference between them so the change should be as simple as changing the import from “import { Link } from 'gatsby’” to “import Link from ‘next/link’” and changing the link destination definition from “to=‘destination’” to “href=‘destination’”.

// Gatsby
<Link to="/about">About</Link>
// Next.js
<Link href="/about">About</Link>

Data Fetching

Gatsby uses useStaticQuery to fetch data at build time and on the client you need to use React's useEffect. In the Next.js App Router you can leverage React server components that can fetch data when they need it with basic fetch requests.

No node APIs or source plugins are needed in Nextjs. For static page content convert useStaticQuery to just an async fetch in the page or in individual components. Nextjs will automatically cache the requests and their result so the queries only need to be re-run if you've specified a revalidation time for them, or if using on-demand revalidation with webhooks or similar.

Here's an example of fetching data in Next.js for a page:

export const Page = async ({ params }) => {
const data = await fetchDataFromDatabase(params.slug);
return (
<Render the page and components here>
);
};

The params include data from the router, for example the previously mentioned getStaticParams passes the slug here which can be used to query your database among other things.

You can also fetch data for individual components in the same way. These fetches are happening only on the server, so they can for example be authenticated without fear of exposing secret tokens to clients. If you need to fetch data on client side, you can still use the same useEffect approach as with Gatsby.

Images

In Gatsby, images are loaded and optimized with the gatsby-image component. Next.js has its own built-in next/image component for loading and optimizing the images. The syntax for them is a bit different. Next.js Image component is used like <Image src={image-source} width={width} height={height} alt="image alt text here" />

SEO Metadata

Both Gatsby and Next.js have built-in Head components that can be used for SEO meta tags. In Next you can import from it next/head and then wrap your meta tags in <Head>. This component can be included in the root layout to include the tags in all pages, and for individual pages you can use the <Head> individually if needed.

Static folder

Lastly you should move your static assets. Next.js uses the public folder for static assets. Gatsby does the same thing with the static folder, so you just need to rename your "static" folder to "public".

Conclusion

After migrating your pages, routes, and assets, you should of course test your application thoroughly. Validate that:

  • All routes resolve as expected

  • Data fetching and caching works as expected

  • Static assets are served from the public folder.

  • Internal links and SEO tags are correctly configured.

This blog post gave you the basic frame for migrating from Gatsby to the more modern and performant Next.js.


If you are planning on migrating your website to Next.js or are looking to build a new site from scratch, feel free to contact us using the form below!

Contact us

Get in touch and let's discuss your business case

Email to sales@ikius.com or send us a message here.

Submitting this form will not sign you up for any marketing lists. Your information is strictly used and stored for contacting you. Privacy Policy