Migrating from Gatsby

    • Choose which data fetching strategy you want on a per-page basis.
    • Use to update existing pages by re-rendering them in the background as traffic comes in.
    • Use API Routes.

    And more! Let’s walk through a series of steps to complete the migration.

    The first step towards migrating to Next.js is to update and dependencies. You should:

    • Remove all Gatsby-related packages (but keep react and react-dom).
    • Install next.
    • Add Next.js related commands to scripts. One is next dev, which runs a development server at localhost:3000. You should also add next build and next start for creating and starting a production build.

    Here’s an example package.json (view diff):

    Static Assets and Compiled Output

    Gatsby uses the public directory for the compiled output, whereas Next.js uses it for static assets. Here are the steps for migration ():

    • Remove .cache/ and public from .gitignore and delete both directories.
    • Rename Gatsby’s static directory as public.
    • Add .next to .gitignore.

    Both Gatsby and Next support a pages directory, which uses file-system based routing. Gatsby’s directory is src/pages, which is also .

    Gatsby creates dynamic routes using the createPages API inside of gatsby-node.js. With Next, we can use Dynamic Routes inside of pages to achieve the same effect. Rather than having a template directory, you can use the React component inside your dynamic route file. For example:

    • Gatsby: createPages API inside gatsby-node.js for each blog post, then have a template file at src/templates/blog-post.js.
    • Next: Create pages/blog/[slug].js which contains the blog post template. The value of slug is accessible through a . For example, the route /blog/first-post would forward the query object { 'slug': 'first-post' } to pages/blog/[slug].js (learn more here).

    With Gatsby, global CSS imports are included in gatsby-browser.js. With Next, you should create a custom _app.js for global CSS. When migrating, you can copy over your CSS imports directly and update the relative file path, if necessary. Next.js has .

    1. // Gatsby
    2. import { Link } from 'gatsby'
    3. export default function Home() {
    4. return <Link to="/blog">blog</Link>
    5. }
    1. // Next.js
    2. import Link from 'next/link'
    3. export default function Home() {
    4. return (
    5. <Link href="/blog">
    6. <a>blog</a>
    7. </Link>
    8. )
    9. }

    Update any import statements, switch to to href, and add an <a> tag as a child of the element.

    The largest difference between Gatsby and Next.js is how data fetching is implemented. Gatsby is opinionated with GraphQL being the default strategy for retrieving data across your application. With Next.js, you get to choose which strategy you want (GraphQL is one supported option).

    Gatsby uses the graphql tag to query data in the pages of your site. This may include local data, remote data, or information about your site configuration. Gatsby only allows the creation of static pages. With Next.js, you can choose on a per-page basis which you want. For example, getServerSideProps allows you to do server-side rendering. If you wanted to generate a static page, you’d export getStaticProps / getStaticPaths inside the page, rather than using pageQuery. For example:

    You’ll commonly see Gatsby plugins used for reading the file system (gatsby-source-filesystem), handling markdown files (gatsby-transformer-remark), and so on. For example, the popular starter blog example has 15 Gatsby specific packages. Next takes a different approach. It includes common features directly inside the framework, and gives the user full control over integrations with external packages. For example, rather than abstracting reading from the file system to a plugin, you can use the native Node.js fs package inside getStaticProps / getStaticPaths to read from the file system.

    1. // Install gray-matter and date-fns
    2. import matter from 'gray-matter'
    3. import { parseISO, format } from 'date-fns'
    4. import fs from 'fs'
    5. import { join } from 'path'
    6. // Add markdown files in `src/content/blog`
    7. const postsDirectory = join(process.cwd(), 'src', 'content', 'blog')
    8. export function getPostBySlug(slug) {
    9. const realSlug = slug.replace(/\.md$/, '')
    10. const fullPath = join(postsDirectory, `${realSlug}.md`)
    11. const { data, content } = matter(fileContents)
    12. const date = format(parseISO(data.date), 'MMMM dd, yyyy')
    13. return { slug: realSlug, frontmatter: { ...data, date }, content }
    14. }
    15. export function getAllPosts() {
    16. const slugs = fs.readdirSync(postsDirectory)
    17. const posts = slugs.map((slug) => getPostBySlug(slug))
    18. return posts
    19. }

    Next.js has a built-in Image Component and Automatic Image Optimization.

    The Next.js Image Component, , is an extension of the HTML <img> element, evolved for the modern web.

    The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like WebP when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats.

    This means you can remove common Gatsby plugins like:

    • gatsby-image
    • gatsby-transformer-sharp
    • gatsby-plugin-sharp

    Instead, use the built-in next/image component and .

    1. import Image from 'next/image'
    2. import profilePic from '../public/me.png'
    3. export default function Home() {
    4. return (
    5. <>
    6. <h1>My Homepage</h1>
    7. <Image
    8. src={profilePic}
    9. alt="Picture of the author"
    10. // When "responsive", similar to "fluid" from Gatsby
    11. // When "intrinsic", similar to "fluid" with maxWidth from Gatsby
    12. // When "fixed", similar to "fixed" from Gatsby
    13. layout="responsive"
    14. // Optional, similar to "blur-up" from Gatsby
    15. placeholder="blur"
    16. // Optional, similar to "width" in Gatsby GraphQL
    17. width={500}
    18. // Optional, similar to "height" in Gatsby GraphQL
    19. height={500}
    20. />
    21. <p>Welcome to my homepage!</p>
    22. </>
    23. )
    24. }

    With Gatsby, your site’s metadata (name, description, etc.) is located inside gatsby-config.js. This is then exposed through the GraphQL API and consumed through a pageQuery or a static query inside a component.

    With Next.js, we recommend creating a config file similar to below. You can then import this file anywhere without having to use GraphQL to access your site’s metadata.

    Most Gatsby examples use react-helmet to assist with adding meta tags for proper SEO. With Next.js, we use next/head to add meta tags to your <head /> element. For example, here’s an SEO component with Gatsby:

    1. // src/components/seo.js
    2. export default function SEO({ description, title, siteTitle }) {
    3. return (
    4. <Helmet
    5. title={title}
    6. titleTemplate={siteTitle ? `%s | ${siteTitle}` : null}
    7. meta={[
    8. {
    9. name: `description`,
    10. content: description,
    11. },
    12. property: `og:title`,
    13. content: title,
    14. },
    15. {
    16. property: `og:description`,
    17. content: description,
    18. },
    19. {
    20. property: `og:type`,
    21. content: `website`,
    22. },
    23. {
    24. name: `twitter:card`,
    25. content: `summary`,
    26. },
    27. {
    28. name: `twitter:creator`,
    29. content: twitter,
    30. },
    31. {
    32. name: `twitter:title`,
    33. content: title,
    34. },
    35. {
    36. name: `twitter:description`,
    37. content: description,
    38. },
    39. ]}
    40. />
    41. )
    42. }

    And here’s the same example using Next.js, including reading from a site config file.

    1. // src/components/seo.js
    2. import Head from 'next/head'
    3. import config from '../config'
    4. export default function SEO({ description, title }) {
    5. const siteTitle = config.title
    6. return (
    7. <Head>
    8. <title>{`${title} | ${siteTitle}`}</title>
    9. <meta name="description" content={description} />
    10. <meta property="og:type" content="website" />
    11. <meta property="og:title" content={title} />
    12. <meta property="og:description" content={description} />
    13. <meta property="og:site_name" content={siteTitle} />
    14. <meta property="twitter:card" content="summary" />
    15. <meta property="twitter:creator" content={config.social.twitter} />
    16. <meta property="twitter:title" content={title} />
    17. <meta property="twitter:description" content={description} />
    18. </Head>
    19. }