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:
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.
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.
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.
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.
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 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.
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()} · 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.
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.
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.
Adding your site to Netlify is as simple as creating an account, linking your GitHub, and clicking the Create site from git button.
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 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.
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:
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
touchNode
and deleteNote
method is now the node itselfWith DSG and SSR, Gatsby now is a complete web development framework for all situations on par with Remix and Next.js.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
2 Replies to "Gatsby: The ultimate guide with examples"
Hi I have a version of node 18.15.0 how do you exactly run this command export NODE_OPTIONS=–no-experimental-fetch
Hey, blogrcoket, if I set window width 1278px and scroll to “What is Gatsby?” the site starts blinking and scrolling becomes super slow(barelly scrolls)