Luke Joliat Liberal Arts fanboy, Catholic, father, tech enthusiast, web developer, senior consultant at Slalom. Find me at lukejoliat.com.

Gatsby: The ultimate guide with examples

9 min read 2764

GatsbyJS Tutorial

Editor’s note: This tutorial was last updated on 9 June 2022 to include more up-to-date information about Gatsby, including information about Gatsby v4.

In this comprehensive Gatsby tutorial, we’ll tell you everything you need to know about the popular React-based framework, including what it is, how to use it, and what distinguishes Gatsby from other static site generators.

We’ll cover the following in detail:

What is Gatsby?

Gatsby is a free, open-source, React-based framework designed to help developers build performant websites and apps. Put simply, Gatsby is a static site generator that leverages React.

Why would you need a framework on top of a framework (or library)? Isn’t React supposed to help developers build websites and apps? This is a reasonable question that is often posed when discussing Gatsby and Next.js.

React is a library that is meant to provide a certain set of core functionality for developers to leverage. It is intended to be lightweight and broadly applicable. Gatsby, on the other hand, is a static progressive web app (PWA) generator that offers code and data splitting out of the box.

To boost performance, Gatsby loads only critical HTML, CSS, JavaScript, and other data. Once loaded, it prefetches resources for other pages you might navigate to. This way, your site loads as fast as possible and user interactions feel seamless.

What are static sites?

Static sites have been around for a very long time. In fact, they are probably the original website: just HTML, CSS, and JavaScript. They are not rendered during runtime; there is no server-side code, no database, etc.

A static site generator is a tool that generates static sites. With regard to JS frameworks and libraries, these usually generate HTML content on the client side during runtime. Static site generators generate this content during build time. Then, once loaded, React takes over, and you have a single-page application!

How is this different from server-side rendering? This is a great question. The main difference is that there is no server-side code. So, unlike a tool such as Next.js, Gatsby does not render anything on the server when a request is made. This is all done at build time of the application.

Some of the benefits of a static site are: speed, search engine optimization, and security. Not only are sites made with Gatsby blazing fast, but they have an implicit security since there is no database or server, and unlike standard React applications, they make SEO much easier since crawlers can find the content.

What makes Gatsby special?

Gatsby has some great features that differentiate it from other static site generators.
First and foremost, Gatsby leverages React, so it is a great choice for those who are comfortable with and love it.

Gatsby pairs really well with platforms like Netlify, and you can easily configure your site to build and deploy every time you commit and push to GitHub.

Gatsby also comes with a great ecosystem of plugins that serve various needs. These plugins can help you source data from CMSs like WordPress or Contentful, help you integrate with tools like Algolia, and manage your images by lazy-loading and optimizing them.

Gatsby also provides a wealth of APIs that make the development of static sites much easier — for example, the createPage API that makes it really easy to transform markdown files into static pages with a template at build time.

Finally, Gatsby has a bunch of great components that simplify things like routing, linking, and handling images, which are not included in the core React library.

Do you need to know React and GraphQL to use Gatsby?

GraphQL is a popular and powerful query language and server-side runtime for executing queries. It isn’t associated with any database or stage engine; instead, GraphQL is backed by your existing code. You can create a GraphQL service by defining types and fields on those types, then providing functions for each field on each type.

Gatsby uses GraphQL to manage data throughout the application. Although you can use Gatsby without GraphQL, using GraphQL really makes app development more declarative and intuitive.



Getting started with Gatsby

To get started using Gatsby, download the Gatsby CLI: npm i -g gatsby. This command-line tool enables you to generate, run, and build a Gatsby application.

To get up and running quickly, you can use the Gatsby default starter repository. After cloning this (click the Use Template button to create your own copy, then do a git clone of your new repo), run npm install and then gatsby develop. This will generate a fully active Gatsby application running on http://localhost:3000.

If you’re running Node v18 you may get the following error:

You must provide the URL of lib/mappings.wasm by calling SourceMapConsumer.initialize({
'lib/mappings.wasm': ... }) before using SourceMapConsumer

To handle this error, you can downgrade to Node v17 or v16 using Node Version Manager or run the following command before running gatsby develop: export NODE_OPTIONS=--no-experimental-fetch. Gatsby has its own fetch implementation that conflicts with the new native Node Fetch API introduced in Node v18.

To confirm that pages have already been rendered, you can visit any of the pages and click View source. Note, though, that you can also click links and the page will update without a full refresh, as you would expect from a PWA.

Designing your site with Gatsby

Designing a look and feel was truthfully the most difficult part of the experience. I felt paralyzed by possibilities to some extent. One thing that helped me move forward was looking at pages and pages of Awwward-winning portfolio websites to gather inspiration and get a sense of the great designs that are out there.

I committed to designing a few of my own custom animations and SVGs. This was quite fun, and I cannot recommend Figma enough for this endeavor. If you are familiar with Sketch, it will be extremely simple to use.

vintage computer figma design

Developing your site with Gatsby

To get off the ground, I used the Gatsby starter repository. I forked this from GitHub and renamed the repo. Then I cloned it and used the Gatsby CLI to build. In a very short time, I was up and running on localhost with a live and hot-reloading application.

The structure of the code is very simple. You have three folders inside the src directory: components, images, and pages. The images directory contains a couple png’s that are used in the site. The components directory contains several components of note.

First, the layout.js component. It is a wrapper component designed to provide styling and functionality across the application. This kind of pattern is very popular in React.

You will notice that there is a binding called {children} in the center of the component:

/**
 * Layout component that queries for data
 * with Gatsby's useStaticQuery component
 *
 * See: https://www.gatsbyjs.com/docs/use-static-query/
 */
import * as React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import Header from "./header"
import "./layout.css"
const Layout = ({ children }) => {
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)
  return (
    <>
      <Header siteTitle={data.site.siteMetadata?.title || `Title`} />
      <div
        style={{
          margin: `0 auto`,
          maxWidth: `var(--size-content)`,
          padding: `var(--size-gutter)`,
        }}
      >
        <main>{children}</main>
        <footer
          style={{
            marginTop: `var(--space-5)`,
            fontSize: `var(--font-sm)`,
          }}
        >
          © {new Date().getFullYear()} &middot; Built with
          {` `}
          <a href="https://www.gatsbyjs.com">gatsbyjs</a>
        </footer>
      </div>
    </>
  )
}
Layout.propTypes = {
  children: PropTypes.node.isRequired,
}
export default Layout

This represents the content to be passed inside the component. You can see this component at work in index.js in the pages directory:

import * as React from "react"
import { Link } from "gatsby"
import { StaticImage } from "gatsby-plugin-image"
import Layout from "../components/layout"
import Seo from "../components/seo"
import * as styles from "../components/index.module.css"
const links = [
  {
    text: "Tutorial",
    url: "https://www.gatsbyjs.com/docs/tutorial",
    description:
      "A great place to get started if you're new to web development. Designed to guide you through setting up your first Gatsby site.",
  },
  {
    text: "Examples",
    url: "https://github.com/gatsbyjs/gatsby/tree/master/examples",
    description:
      "A collection of websites ranging from very basic to complex/complete that illustrate how to accomplish specific tasks within your Gatsby sites.",
  },
  {
    text: "Plugin Library",
    url: "https://www.gatsbyjs.com/plugins",
    description:
      "Learn how to add functionality and customize your Gatsby site or app with thousands of plugins built by our amazing developer community.",
  },
  {
    text: "Build and Host",
    url: "https://www.gatsbyjs.com/cloud",
    description:
      "Now you’re ready to show the world! Give your Gatsby site superpowers: Build and host on Gatsby Cloud. Get started for free!",
  },
]
const samplePageLinks = [
  {
    text: "Page 2",
    url: "page-2",
    badge: false,
    description:
      "A simple example of linking to another page within a Gatsby site",
  },
  { text: "TypeScript", url: "using-typescript" },
  { text: "Server Side Rendering", url: "using-ssr" },
  { text: "Deferred Static Generation", url: "using-dsg" },
]
const moreLinks = [
  { text: "Join us on Discord", url: "https://gatsby.dev/discord" },
  {
    text: "Documentation",
    url: "https://gatsbyjs.com/docs/",
  },
  {
    text: "Starters",
    url: "https://gatsbyjs.com/starters/",
  },
  {
    text: "Showcase",
    url: "https://gatsbyjs.com/showcase/",
  },
  {
    text: "Contributing",
    url: "https://www.gatsbyjs.com/contributing/",
  },
  { text: "Issues", url: "https://github.com/gatsbyjs/gatsby/issues" },
]
const utmParameters = `?utm_source=starter&utm_medium=start-page&utm_campaign=default-starter`
const IndexPage = () => (
  <Layout>
    <Seo title="Home" />
    <div className={styles.textCenter}>
      <StaticImage
        src="../images/example.png"
        loading="eager"
        width={64}
        quality={95}
        formats={["auto", "webp", "avif"]}
        alt=""
        style={{ marginBottom: `var(--space-3)` }}
      />
      <h1>
        Welcome to <b>Gatsby!</b>
      </h1>
      <p className={styles.intro}>
        <b>Example pages:</b>{" "}
        {samplePageLinks.map((link, i) => (
          <React.Fragment key={link.url}>
            <Link to={link.url}>{link.text}</Link>
            {i !== samplePageLinks.length - 1 && <> · </>}
          </React.Fragment>
        ))}
        <br />
        Edit src/pages/index.js to update this page. </p> </div> <ul className={styles.list}> {links.map(link => ( <li key={link.url} className={styles.listItem}> <a className={styles.listItemLink} href={`${link.url}${utmParameters}`} > {link.text} ↗ </a> <p className={styles.listItemDescription}>{link.description}</p> </li> ))} </ul> {moreLinks.map((link, i) => ( <React.Fragment key={link.url}> <a href={`${link.url}${utmParameters}`}>{link.text}</a> {i !== moreLinks.length - 1 && <> · </>} </React.Fragment> ))} </Layout> ) export default IndexPage

The other noteworthy component is seo.js:

/**
 * SEO component that queries for data with
 *  Gatsby's useStaticQuery React hook
 *
 * See: https://www.gatsbyjs.com/docs/use-static-query/
 */
import * as React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"
function Seo({ description, lang, meta, title }) {
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )
  const metaDescription = description || site.siteMetadata.description
  const defaultTitle = site.siteMetadata?.title
  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      titleTemplate={defaultTitle ? `%s / ${defaultTitle}` : null}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          name: `twitter:card`,
          content: `summary`,
        },
        {
          name: `twitter:creator`,
          content: site.siteMetadata?.author || ``,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
      ].concat(meta)}
    />
  )
}
Seo.defaultProps = {
  lang: `en`,
  meta: [],
  description: ``,
}
Seo.propTypes = {
  description: PropTypes.string,
  lang: PropTypes.string,
  meta: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
}
export default Seo

This component shows a couple interesting things. First, it gives a bit of visibility into how GraphQL is used within Gatsby. The useStaticQuery call at line 10 of the component is designed to pull in the siteMetadata from gatsby-config.js at build time. The data from this query is then passed in to the component via props.

Under pages, you have the main index.js, a secondary page, and a 404 page. In index.js, you can see how the layout component is put to work, and also how you can link to other pages such as page-2.js using Gatsby’s Link component. Anything in this folder will be transformed into static pages by Gatsby at build time.

This provides a lot of what you need out of the box. You can get to work building pages and components straightaway. However, if you want to dynamically create pages from, say markdown files, you can follow this simple tutorial on Gatsby’s website.

Searching your Gatsby site

One of the downsides of not having a server is that searching your site isn’t straightforward. This can be circumvented by using a tool like Algolia. Gatsby has some great guides to implementing this feature with Algolia or other tools like Lunr and ElasticSearch.

Gatsby Example: Searching

Deploying your Gatsby site

Once you’ve created a site, you need to think about how to host it. There are two great options that lead the pack: GitHub Pages and Netlify.

I went with Netlify because they provide continuous deployment (Git-triggered builds), a global CDN, full DNS, automated HTTPS, and a lot more.

Their free tier includes “unlimited personal and commercial projects, HTTPS, continuous deployment from public or private repos, and more.” I was also able to easily purchase the domain name I needed through Netlify. It was essentially a one-stop shop for everything I needed to get my site live.


More great articles from LogRocket:


Adding your site to Netlify is as simple as creating an account, linking your GitHub, and clicking the Create site from git button.

Is Gatsby dead?

With all the hype surrounding Next.js and Remix one may ask, is there still room for Gatsby? The answer is a resounding yes.

Looking at the Gatsby library page on npm, the core library still holds a very strong average of 400k downloads every week, and with the Gatsby Cloud service that tailors hosting to the Gatsby framework you have tooling and support that will keep Gatsby going strong into the foreseeable future.

Should you use Gatsby?

Should I have gone with another generator? Should I have just built a site with React or Next.js? Gatsby has advantages and downsides. However, many of the downsides are minimized by certain use cases. For the creation of a personal site, Gatsby turned out to be the perfect choice for me.

The workflow is extremely simple: when I make changes and push them to GitHub, my site is redeployed. I don’t need to concern myself too much with infrastructure, etc. Netlify handles all that for me.

It maintains a great balance between allowing me to code and reducing boilerplate code.
I love the gatsby-image plugin, and the ability to use GraphQL really simplifies passing data into my components.

The only thing I didn’t love was that some of the configuration required in files like gatsby-node.js didn’t seem all that intuitive to me.

In conclusion, I would really recommend Gatsby to those looking for a candidate to develop smaller sites like portfolios and personal blogs . It really shines in these use cases.

Gatsby carries with it all the benefits of static websites, such as speed, security, and SEO, and it is especially wonderful for those who like to do a bit of coding and don’t want to just use WordPress or SquareSpace.

What’s new with Gatsby v4?

Since this article was originally written, Gatsby has released a new major version, bringing many new cutting edge features to the Gatsby platform such as:

  • Parallel querying, to speed up query times by up to 40 percent
  • Deferred static generation to statically generate the page upon first user request instead of at build time
  • Server-side rendering for pages that are rendered on each user request (great for pages with lots of dynamic content)

But like any major release it comes with changes that would break codebases from v3 without following this migration guide. Some standout changes to keep in mind are as follows:

  • createFieldExtension, createTypes and addThirdPartySchema have been deprecated in favor of the new createSchemaCustomization and createResolvers
  • Arguments to the touchNode and deleteNote method is now the node itself

With DSG and SSR, Gatsby now is a complete web development framework for all situations on par with Remix and Next.js.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Luke Joliat Liberal Arts fanboy, Catholic, father, tech enthusiast, web developer, senior consultant at Slalom. Find me at lukejoliat.com.

Leave a Reply