Skip to content

Migrating from Gatsby

Here are some key concepts and migration strategies to help you get started. Use the rest of our docs and our Discord community to keep going!

Key Similarities between Gatsby and Astro

Section titled Key Similarities between Gatsby and Astro

Gatsby and Astro share some similarities that will help you migrate your project:

Key Differences between Gatsby and Astro

Section titled Key Differences between Gatsby and Astro

When you rebuild your Gatsby site in Astro, you will notice some important differences:

  • Gatsby projects are React single-page apps and use index.js as your project’s root. Astro projects are multi-page sites, and index.astro is your home page.

  • Astro components are not written as exported functions that return page templating. Instead, you’ll split your code into a “code fence” for your JavaScript and a body exclusively for the HTML you generate.

  • Local file data: Gatsby uses GraphQL to retrieve data from your project files. Astro uses ESM imports and top-level await functions (e.g. import.meta.glob(), getCollection()) to import data from your project files. You can manually add GraphQL to your Astro project but it is not included by default.

Each project migration will look different, but there are some common actions you will perform when converting from Gatsby to Astro.

Use the create astro command for your package manager to launch Astro’s CLI wizard or choose a community theme from the Astro Theme Showcase.

You can pass a --template argument to the create astro command to start a new Astro project with one of our official starters (e.g. docs, blog, portfolio). Or, you can start a new project from any existing Astro repository on GitHub.

Terminal window
# launch the Astro CLI Wizard
npm create astro@latest
# create a new project with an official example
npm create astro@latest -- --template <example-name>

Then, copy your existing Gatsby project files over to your new Astro project into a separate folder outside of src.

Install integrations (optional)

Section titled Install integrations (optional)

You may find it useful to install some of Astro’s optional integrations to use while converting your Gatsby project to Astro:

  • @astrojs/react: to reuse some existing React UI components in your new Astro site or keep writing with React components.

  • @astrojs/mdx: to bring existing MDX files from your Gatsby project, or to use MDX in your new Astro site.

Following Astro’s project structure:

  1. Delete Gatsby’s public/ folder.

    Gatsby uses the public/ directory for its build output, so you can safely discard this folder. You will no longer need a built version of your Gatsby site. (Astro uses dist/ by default for the build output.)

  2. Rename Gatsby’s static/ folder to public/, and use it as Astro’s public/ folder.

    Astro uses a folder called public/ for static assets. You can alternatively copy the contents of static/ into your existing Astro public/ folder.

  3. Copy or Move Gatsby’s other files and folders (e.g. components, pages, etc.) as needed into your Astro src/ folder as you rebuild your site, following Astro’s project structure.

    Astro’s src/pages/ folder is a special folder used for file-based routing to create your site’s pages and posts from .astro, .md and .mdx files. You will not have to configure any routing behavior for your Astro, Markdown, and MDX files.

    All other folders are optional, and you can organize the contents of your src/ folder any way you like. Other common folders in Astro projects include src/layouts/, src/components, src/styles, and src/scripts.

Tips: Convert JSX files to .astro files

Section titled Tips: Convert JSX files to .astro files

Here are some tips for converting a Gatsby .js component into a .astro component:

  1. Use only the return() of the existing Gatsby component function as your HTML template.

  2. Change any Gatsby or JSX syntax to Astro syntax or to HTML web standards. This includes <Link to="">, {children}, and className, for example.

  3. Move any necessary JavaScript, including import statements, into a “code fence” (---). Note: JavaScript to conditionally render content is often written inside the HTML template directly in Astro.

  4. Use Astro.props to access any additional props that were previously passed to your Gatsby function.

  5. Decide whether any imported components also need to be converted to Astro. With the official React integration installed, you can use existing React components in your Astro files. But, you may want to convert them to .astro components, especially if they do not need to be interactive!

  6. Remove any GraphQL queries. Instead, use import and import.meta.glob() statements to query your local files.

See an example from Gatsby’s Blog starter template converted step-by-step

Compare the following Gatsby component and a corresponding Astro component:

component.jsx
import * as React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Header from "./header"
import Footer from "./footer"
import "./layout.css"
const Component = ({ message, children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div style={{ margin: `0`, maxWidth: `960`}}>{message}</div>
<main>{children}</main>
<Footer siteTitle={data.site.siteMetadata} />
</>
)
}
export default Component

You may find it helpful to start by converting your Gatsby layouts and templates into Astro layout components.

Each Astro page explicitly requires <html>, <head>, and <body> tags to be present, so it is common to reuse a layout file across pages. Astro uses a <slot /> instead of React’s {children} prop for page content, with no import statement required. Your Gatsby layout.js and templates will not include these.

Note the standard HTML templating, and direct access to <head>:

src/layouts/Layout.astro
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<title>Astro</title>
</head>
<body>
<!-- Wrap the slot element with your existing layout templating -->
<slot />
</body>
</html>

You may also wish to reuse code from Gatsby’s src/components/seo.js to include additional site metadata. Notice that Astro uses neither <Helmet> nor <Header> but instead creates <head> directly. You may import and use components, even within <head>, to separate and organize your page content.

In Gatsby, your pages and posts may exist in src/pages/ or outside of src in another folder, like content. In Astro, all your page content must live within src/.

Your existing Gatsby JSX (.js) pages will need to be converted from JSX files to .astro pages. You cannot use an existing JSX page file in Astro.

These .astro pages must be located within src/pages/ and will have page routes generated automatically based on their file path.

Astro has built-in support for Markdown and an optional integration for MDX files. Your existing Markdown and MDX files can be reused but may require some adjustments to their frontmatter, such as adding Astro’s special layout frontmatter property. They can also be placed within src/pages/ to take advantage of automatic file-based routing.

Alternatively, you can use content collections in Astro to store and manage your content. You will retrieve the content yourself and generate those pages dynamically.

As Astro outputs raw HTML, it is possible to write end-to-end tests using the output of the build step. Any end-to-end tests written previously might work out-of-the-box if you have been able to match the markup of the older Gatsby site. Testing libraries such as Jest and React Testing Library can be imported and used in Astro to test your React components.

See Astro’s testing guide for more.

Gatsby has several top-level configuration files that also include site and page metadata and are used for routing. You will not use any of these gatsby-*.js files in your Astro project, but there may be some content that you can reuse as you build your Astro project:

  • gatsby-config.js: Move your siteMetadata: {} into src/data/siteMetadata.js (or siteMetadata.json) to import data about your site (title, description, social accounts, etc.) into page layouts.

  • gatsby-browser.js: Consider adding anything used here directly into your main layout’s <head> tag.

  • gatsby-node.js: You will not need to create your own nodes in Astro, but viewing the schema in this file may help you with defining types in your Astro project.

  • gatsby-ssr.js: If you choose to use SSR in Astro, you will add and configure the SSR adapter of your choice directly in astro.config.mjs.

Reference: Convert to Astro Syntax

Section titled Reference: Convert to Astro Syntax

The following are some examples of Gatsby-specific syntax that you will need to convert to Astro. See more differences between Astro and JSX in the guide to writing Astro components.

Convert any Gatsby <Link to="">, <NavLink> etc. components to HTML <a href=""> tags.

<Link to="/blog">Blog</Link>
<a href="/blog">Blog</a>

Astro does not use any special component for links, although you are welcome to build your own <Link> component. You can then import and use this <Link> just as you would any other component.

src/components/Link.astro
---
const { to } = Astro.props
---
<a href={to}><slot /></a>

If necessary, update any file imports to reference relative file paths exactly. This can be done using import aliases, or by writing out a relative path in full.

Note that .astro and several other file types must be imported with their full file extension.

src/pages/authors/Fred.astro
---
import Card from `../../components/Card.astro`;
---
<Card />

Gatsby Children Props to Astro

Section titled Gatsby Children Props to Astro

Convert any instances of {children} to an Astro <slot />. Astro does not need to receive {children} as a function prop and will automatically render child content in a <slot />.

src/components/MyComponent
---
---
export default function MyComponent(props) {
return (
<div>
{props.children}
</div>
);
}
<div>
<slot />
</div>

React components that pass multiple sets of children can be migrated to an Astro component using named slots.

See more about specific <slot /> usage in Astro.

You may need to replace any CSS-in-JS libraries (e.g. styled-components) with other available CSS options in Astro.

If necessary, convert any inline style objects (style={{ fontWeight: "bold" }}) to inline HTML style attributes (style="font-weight:bold;"). Or, use an Astro <style> tag for scoped CSS styles.

src/components/Card.astro
<div style={{backgroundColor: `#f4f4f4`, padding: `1em`}}>{message}</div>
<div style="background-color: #f4f4f4; padding: 1em;">{message}</div>

Tailwind is supported after installing the Tailwind integration. No changes to your existing Tailwind code are required!

Global styling is achieved in Gatsby using CSS imports in gatsby-browser.js. In Astro, you will import .css files directly into a main layout component to achieve global styles.

See more about Styling in Astro.

Convert Gatsby’s <StaticImage /> and <GatsbyImage /> components to Astro’s own image integration components, or to a standard HTML <img> / JSX <img /> tag as appropriate in your React components.

src/pages/index.astro
---
import { Image } from 'astro:assets';
import rocket from '../assets/rocket.png';
---
<Image src={rocket} alt="A rocketship in space." />
<img src={rocket.src} alt="A rocketship in space.">

Astro’s <Image /> component works in .astro and .mdx files only. See a full list of its component attributes and note that several will differ from Gatsby’s attributes.

To continue using images in Markdown (.md) files using standard Markdown syntax (![]()), you may need to update the link. Using the HTML <img> tag directly is not supported in .md files for local images, and must be converted to Markdown syntax.

src/pages/post-1.md
# My Markdown Page
<!-- Local image stored at src/assets/stars.png -->
![A starry night sky.](../assets/stars.png)

In React (.jsx) components, use standard JSX image syntax (<img />). Astro will not optimize these images, but you can install and use NPM packages for more flexibility.

You can learn more about using images in Astro in the Images Guide.

Remove all references to GraphQL queries, and instead use import.meta.glob() to access data from your local files.

Or, if using content collections, query your Markdown and MDX files using getEntry() and getCollection().

These data requests are made in the frontmatter of the Astro component using the data.

src/pages/index.astro
---
import { graphql } from "gatsby"
import { getCollection } from 'astro:content';
// Get all `src/content/blog/` entries
const allBlogPosts = await getCollection('blog');
// Get all `src/pages/posts/` entries
const allPosts = await Object.values(await import.meta.glob('../pages/post/*.md', { eager: true }));
---
export const pageQuery = graphql`
{
allMarkdownRemark(sort: { frontmatter: { date: DESC } }) {
nodes {
excerpt
fields {
slug
}
frontmatter {
date(formatString: "MMMM DD, YYYY")
title
description
}
}
}
}
`

Guided example: Gatsby layout to Astro

Section titled Guided example: Gatsby layout to Astro

This example converts the main project layout (layout.js) from Gatsby’s blog starter to src/layouts/Layout.astro.

This page layout shows one header when visiting the home page, and a different header with a link back to Home for all other pages.

  1. Identify the return() JSX.

    layout.js
    import * as React from "react"
    import { Link } from "gatsby"
    const Layout = ({ location, title, children }) => {
    const rootPath = `${__PATH_PREFIX__}/`
    const isRootPath = location.pathname === rootPath
    let header
    if (isRootPath) {
    header = (
    <h1 className="main-heading">
    <Link to="/">{title}</Link>
    </h1>
    )
    } else {
    header = (
    <Link className="header-link-home" to="/">
    Home
    </Link>
    )
    }
    return (
    <div className="global-wrapper" data-is-root-path={isRootPath}>
    <header className="global-header">{header}</header>
    <main>{children}</main>
    <footer>
    © {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.gatsbyjs.com">Gatsby</a>
    </footer>
    </div>
    )
    }
    export default Layout
  2. Create Layout.astro and add this return value, converted to Astro syntax.

    Note that:

    • {new Date().getFullYear()} just works 🎉
    • {children} becomes <slot /> 🦥
    • className becomes class 📛
    • Gatsby becomes Astro 🚀
    src/layouts/Layout.astro
    ---
    ---
    <div class="global-wrapper" data-is-root-path={isRootPath}>
    <header class="global-header">{header}</header>
    <main><slot /></main>
    <footer>
    © {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.astro.build">Astro</a>
    </footer>
    </div>
  3. Add a page shell so that your layout provides each page with the necessary parts of an HTML document:

    src/layouts/Layout.astro
    ---
    ---
    <html>
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro</title>
    </head>
    <body>
    <div class="global-wrapper" data-is-root-path={isRootPath}>
    <header class="global-header">{header}</header>
    <main>
    <slot />
    </main>
    <footer>
    &#169; {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.astro.build">Astro</a>
    </footer>
    </div>
    </body>
    </html>
  4. Add any needed imports, props, and JavaScript

    To conditionally render a header based on the page route and title in Astro:

    • Provide the props via Astro.props. (Remember: your Astro templating accesses props from its frontmatter, not passed into a function.)
    • Use a ternary operator to show one heading if this is the home page, and a different heading otherwise.
    • Remove variables for {header} and {isRootPath} as they are no longer needed.
    • Replace Gatsby’s <Link/> tags with <a> anchor tags.
    • Use class instead of className.
    • Import a local stylesheet from your project for the class names to take effect.
    src/layouts/Layout.astro
    ---
    import '../styles/style.css';
    const { title, pathname } = Astro.props
    ---
    <html>
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro</title>
    </head>
    <body>
    <div class="global-wrapper">
    <header class="global-header">
    { pathname === "/"
    ?
    <h1 class="main-heading">
    <a href="/">{title}</a>
    </h1>
    :
    <h1 class="main-heading">
    <a class="header-link-home" href="/">Home</a>
    </h1>
    }
    </header>
    <main>
    <slot />
    </main>
    <footer>
    &#169; {new Date().getFullYear()}, Built with
    {` `}
    <a href="https://www.astro.build">Astro</a>
    </footer>
    </div>
    </body>
    </html>
  5. Update index.astro to use this new layout and pass it the necessary title and pathname props:

    src/pages/index.astro
    ---
    import Layout from '../layouts/Layout.astro';
    const pagePathname = Astro.url.pathname
    ---
    <Layout title="Home Page" pathname={pagePathname}>
    <p>Astro</p>
    </Layout>
  6. To test the conditional header, create a second page, about.astro using the same pattern:

    src/pages/about.astro
    ---
    import Layout from '../layouts/Layout.astro';
    const pagePathname = Astro.url.pathname
    ---
    <Layout title="About" pathname={pagePathname}>
    <p>About</p>
    </Layout>

    You should see a link to “Home” only when visiting the About page.

More migration guides

Contribute

What’s on your mind?

Create GitHub Issue

Quickest way to alert our team of a problem.

Community