DevToolBoxGRATIS
Blogg

Gatsby.js: The Complete Guide to the React Static Site Generator

20 min readby DevToolBox Team

TL;DR

Gatsby.js is a React-based static site generator powered by a GraphQL data layer that unifies content from any source. It excels at building high-performance content sites with its rich plugin ecosystem, automatic image optimization, and pre-rendering. While Next.js and Astro have overtaken it in popularity, Gatsby remains strong for projects needing unified data sourcing and mature tooling. This guide covers project setup, GraphQL queries, plugins, SSR/DSG, headless CMS integration, deployment, and framework comparisons.

Key Takeaways

  • Gatsby uses a built-in GraphQL data layer to pull content from files, CMSs, APIs, and databases into a unified schema
  • The plugin ecosystem includes 2,800+ plugins for sourcing data, transforming content, and optimizing output
  • Automatic image optimization generates responsive sizes, modern formats (WebP/AVIF), and lazy loading
  • SSR and DSG modes extend Gatsby beyond pure static generation for dynamic and large-scale sites
  • Gatsby Head API provides per-page SEO metadata with zero runtime overhead
  • Headless CMS integration (Contentful, Sanity, WordPress) works through dedicated source plugins
  • Deploy to any static host; use Netlify or Vercel for SSR/DSG support

What Is Gatsby.js?

Gatsby.js is an open-source framework built on React that generates static HTML pages at build time. Unlike server-rendered applications that build pages on every request, Gatsby pre-renders your entire site into optimized static files that load instantly and score high on Core Web Vitals.

What sets Gatsby apart is its GraphQL data layer. Every data source, whether local Markdown files, a headless CMS, or a REST API, gets pulled into a unified GraphQL schema at build time. You write GraphQL queries to fetch exactly the data you need for each page.

Project Setup and Structure

# Install the Gatsby CLI and create a new project
npm install -g gatsby-cli
gatsby new my-gatsby-site
cd my-gatsby-site

# Development server at localhost:8000
gatsby develop

# Production build
gatsby build
gatsby serve

# Project structure:
# my-gatsby-site/
# ├── src/
# │   ├── pages/          # File-based routing
# │   ├── components/     # Reusable React components
# │   ├── templates/      # Templates for programmatic pages
# │   └── images/         # Static images
# ├── static/             # Files copied to public/ as-is
# ├── gatsby-config.js    # Plugins and site metadata
# ├── gatsby-node.js      # Build-time APIs (createPages)
# ├── gatsby-browser.js   # Browser APIs
# └── gatsby-ssr.js       # SSR APIs

The GraphQL Data Layer

At build time, Gatsby collects data from all configured source plugins and creates a unified GraphQL schema. You can explore this schema using the built-in GraphiQL IDE at localhost:8000/___graphql during development.

Page Queries and useStaticQuery

// src/pages/index.js - Page Query (top-level pages only)
import React from "react"
import { graphql } from "gatsby"

export default function HomePage({ data }) {
  const posts = data.allMarkdownRemark.nodes
  return (
    <div>
      <h1>My Blog</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.frontmatter.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  )
}

export const query = graphql`
  query HomePageQuery {
    allMarkdownRemark(sort: { frontmatter: { date: DESC } }) {
      nodes {
        id
        excerpt(pruneLength: 200)
        frontmatter {
          title
          date(formatString: "MMMM DD, YYYY")
          slug
        }
      }
    }
  }
`
// src/components/SiteHeader.js - useStaticQuery (any component)
import React from "react"
import { useStaticQuery, graphql } from "gatsby"

export default function SiteHeader() {
  const data = useStaticQuery(graphql`
    query {
      site {
        siteMetadata { title, description }
      }
    }
  `)
  return (
    <header>
      <h1>{data.site.siteMetadata.title}</h1>
      <p>{data.site.siteMetadata.description}</p>
    </header>
  )
}

The Plugin Ecosystem

Gatsby plugins are npm packages that implement Gatsby APIs. Source plugins bring data into GraphQL, transformer plugins convert data nodes into usable formats, and general plugins add capabilities like analytics or SEO.

Essential Plugins

PluginTypePurpose
gatsby-source-filesystemSourceRead local files (Markdown, images, JSON)
gatsby-source-contentfulSourcePull content from Contentful CMS
gatsby-source-wordpressSourcePull content from WordPress
gatsby-source-sanitySourcePull content from Sanity.io
gatsby-transformer-remarkTransformerParse Markdown to HTML with frontmatter
gatsby-plugin-mdxTransformerMDX support (Markdown + JSX)
gatsby-transformer-sharpTransformerProcess images for optimization
gatsby-plugin-imageGeneralResponsive image components
gatsby-plugin-sharpGeneralImage processing engine
gatsby-plugin-sitemapGeneralAuto-generate XML sitemap
gatsby-plugin-manifestGeneralPWA manifest file
gatsby-plugin-offlineGeneralService worker for offline support

gatsby-config.js Example

// gatsby-config.js
module.exports = {
  siteMetadata: {
    title: "My Gatsby Site",
    description: "A blazing fast site built with Gatsby",
    siteUrl: "https://example.com",
  },
  plugins: [
    {
      resolve: "gatsby-source-filesystem",
      options: { name: "blog", path: "./content/blog" },
    },
    {
      resolve: "gatsby-source-filesystem",
      options: { name: "images", path: "./src/images" },
    },
    {
      resolve: "gatsby-transformer-remark",
      options: {
        plugins: [
          "gatsby-remark-prismjs",
          "gatsby-remark-images",
          "gatsby-remark-autolink-headers",
        ],
      },
    },
    "gatsby-plugin-image",
    "gatsby-plugin-sharp",
    "gatsby-transformer-sharp",
    "gatsby-plugin-sitemap",
    {
      resolve: "gatsby-plugin-manifest",
      options: {
        name: "My Gatsby Site",
        short_name: "GatsbySite",
        start_url: "/",
        icon: "src/images/icon.png",
      },
    },
  ],
}

Image Optimization

The gatsby-plugin-image package automatically generates responsive images at multiple sizes, converts to WebP and AVIF, and creates blur-up or traced SVG placeholders. StaticImage handles fixed paths; GatsbyImage handles dynamic images from GraphQL.

import { StaticImage } from "gatsby-plugin-image"
import { GatsbyImage, getImage } from "gatsby-plugin-image"

// StaticImage: known path at build time
function Hero() {
  return (
    <StaticImage
      src="../images/hero.jpg"
      alt="Hero banner"
      layout="fullWidth"
      placeholder="blurred"
      formats={["auto", "webp", "avif"]}
    />
  )
}

// GatsbyImage: dynamic source from GraphQL
function BlogPost({ data }) {
  const image = getImage(data.markdownRemark.frontmatter.cover)
  return <GatsbyImage image={image} alt="Post cover" />
}

// GraphQL query for dynamic images
// export const query = graphql`
//   query($id: String!) {
//     markdownRemark(id: { eq: $id }) {
//       frontmatter {
//         cover {
//           childImageSharp {
//             gatsbyImageData(
//               width: 800
//               placeholder: BLURRED
//               formats: [AUTO, WEBP, AVIF]
//             )
//           }
//         }
//       }
//     }
//   }
// `

Routing and Page Creation

Gatsby supports file-based routing (files in src/pages become routes) and programmatic page creation via the createPages API in gatsby-node.js for dynamic content like blog posts and category pages.

// gatsby-node.js - Programmatic page creation
const path = require("path")

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const template = path.resolve("src/templates/blog-post.js")

  const result = await graphql(`
    query {
      allMarkdownRemark {
        nodes {
          id
          frontmatter { slug, tags }
        }
      }
    }
  `)

  // Create a page for each blog post
  result.data.allMarkdownRemark.nodes.forEach(node => {
    createPage({
      path: "/blog/" + node.frontmatter.slug,
      component: template,
      context: { id: node.id },
    })
  })

  // Create tag archive pages
  const tags = new Set()
  result.data.allMarkdownRemark.nodes.forEach(node => {
    if (node.frontmatter.tags) {
      node.frontmatter.tags.forEach(tag => tags.add(tag))
    }
  })
  tags.forEach(tag => {
    createPage({
      path: "/tags/" + tag.toLowerCase(),
      component: path.resolve("src/templates/tag-page.js"),
      context: { tag },
    })
  })
}

SEO in Gatsby

Gatsby is inherently SEO-friendly because it pre-renders pages to static HTML. Gatsby 4.19+ introduced the Head API as a built-in replacement for react-helmet, providing simpler metadata management with zero runtime cost.

// Gatsby Head API - named export controls <head>
export function Head({ data }) {
  const post = data.markdownRemark.frontmatter
  return (
    <>
      <title>{post.title + " | My Site"}</title>
      <meta name="description" content={post.excerpt} />
      <meta property="og:title" content={post.title} />
      <meta property="og:type" content="article" />
      <link rel="canonical" href={"https://example.com/blog/" + post.slug} />
    </>
  )
}

// Reusable SEO component
function Seo({ title, description, pathname }) {
  const { site } = useStaticQuery(graphql`
    query { site { siteMetadata { title, siteUrl } } }
  `)
  const fullTitle = title
    ? title + " | " + site.siteMetadata.title
    : site.siteMetadata.title
  const url = site.siteMetadata.siteUrl + (pathname || "")

  return (
    <>
      <title>{fullTitle}</title>
      <meta name="description" content={description} />
      <meta property="og:title" content={fullTitle} />
      <link rel="canonical" href={url} />
    </>
  )
}

SSR and Deferred Static Generation (DSG)

Gatsby 4 introduced SSR (pages rendered per request) and DSG (pages built on first request, then cached). SSR enables personalized content; DSG reduces build times for large sites by deferring low-traffic pages.

// SSR: Export getServerData to render per request
// src/pages/dashboard.js
export default function Dashboard({ serverData }) {
  return <h1>Welcome, {serverData.user.name}</h1>
}

export async function getServerData({ headers }) {
  const res = await fetch("https://api.example.com/user", {
    headers: { Authorization: headers.get("cookie") },
  })
  return { props: { user: await res.json() } }
}

// DSG: Set defer: true in createPages
// gatsby-node.js
exports.createPages = async ({ graphql, actions }) => {
  const result = await graphql(`
    query { allMarkdownRemark {
      nodes { id, frontmatter { slug, date } }
    }}
  `)

  const cutoff = new Date()
  cutoff.setMonth(cutoff.getMonth() - 1)

  result.data.allMarkdownRemark.nodes.forEach(node => {
    const isOld = new Date(node.frontmatter.date) < cutoff
    actions.createPage({
      path: "/blog/" + node.frontmatter.slug,
      component: require.resolve("./src/templates/post.js"),
      context: { id: node.id },
      defer: isOld,  // Old posts built on first request
    })
  })
}

Headless CMS Integration

Source plugins pull CMS content into GraphQL, letting you query it like any other data source. Content editors work in the CMS while developers build with React.

// Contentful integration
// gatsby-config.js
module.exports = {
  plugins: [{
    resolve: "gatsby-source-contentful",
    options: {
      spaceId: process.env.CONTENTFUL_SPACE_ID,
      accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
    },
  }],
}

// Query Contentful data in templates
import { renderRichText } from "gatsby-source-contentful/rich-text"

export default function Post({ data }) {
  const post = data.contentfulBlogPost
  return (
    <article>
      <h1>{post.title}</h1>
      <GatsbyImage image={getImage(post.heroImage)} alt={post.title} />
      <div>{renderRichText(post.body)}</div>
    </article>
  )
}

export const query = graphql`
  query($id: String!) {
    contentfulBlogPost(id: { eq: $id }) {
      title
      heroImage { gatsbyImageData(layout: FULL_WIDTH) }
      body { raw }
    }
  }
`

Performance Optimization

Gatsby includes many optimizations out of the box: automatic code splitting per route, prefetching of linked pages, image optimization, and critical CSS inlining.

  • Code Splitting: Each page loads only its required JavaScript; shared code is extracted into common chunks
  • Prefetching: Resources for linked pages are prefetched when links enter the viewport
  • Image Pipeline: Responsive sizes, WebP/AVIF, lazy loading, and blur-up placeholders
  • Static HTML: Pre-rendered HTML means no server round trips and immediate content display
  • Asset Fingerprinting: Content hashes enable aggressive long-term caching
// gatsby-config.js - Build performance flags
module.exports = {
  flags: {
    PARALLEL_SOURCING: true,  // Parallel data sourcing
  },
  plugins: [{
    resolve: "gatsby-plugin-sharp",
    options: {
      defaults: {
        formats: ["auto", "webp"],
        placeholder: "dominantColor",
        quality: 80,
        breakpoints: [750, 1080, 1366, 1920],
      },
    },
  }],
}

Deployment

Gatsby outputs static files that deploy to any host. SSR and DSG require serverless function support. Netlify acquired Gatsby in 2023 and integrated Gatsby Cloud features into their platform.

PlatformSSGSSR/DSGNotes
NetlifyYesYesBest Gatsby support (acquired Gatsby)
VercelYesYesServerless functions for SSR/DSG
AWS S3 + CloudFrontYesNoLow cost, static-only
Cloudflare PagesYesPartialGlobal CDN, generous free tier
GitHub PagesYesNoFree for open source
# Netlify deployment with SSR/DSG support
npm install gatsby-adapter-netlify

// gatsby-config.js
const { NetlifyAdapter } = require("gatsby-adapter-netlify")
module.exports = {
  adapter: NetlifyAdapter(),
  // ... plugins
}

# netlify.toml
[build]
  command = "gatsby build"
  publish = "public"

[[headers]]
  for = "/static/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

Gatsby vs Next.js vs Astro

FeatureGatsby 5Next.js 15Astro 5
Primary UseMulti-source content sitesFull-stack web appsContent-focused static sites
Data LayerBuilt-in GraphQLBring your ownContent Collections
RenderingSSG, SSR, DSGSSG, SSR, ISR, RSCSSG, SSR (on-demand)
Client JS~80 KB (React)~85 KB (React)0 KB (zero JS default)
UI FrameworkReact onlyReact onlyAny (React, Vue, Svelte)
Plugin Count2,800+ pluginsnpm ecosystemGrowing integrations
Image HandlingExcellent (built-in)Good (next/image)Good (astro:assets)
Build SpeedModerate (DSG helps)Fast (ISR)Very fast
Learning CurveModerate (GraphQL)ModerateLow (HTML-first)
CommunityLarge but decliningVery largeRapidly growing

When to Choose Each Framework

Choose Gatsby when: You aggregate data from multiple sources, want a mature plugin ecosystem, are comfortable with GraphQL, and are building content-heavy sites with automatic image optimization.

Choose Next.js when: You need dynamic web apps with authentication, real-time features, React Server Components, ISR, or prefer bringing your own data fetching strategy.

Choose Astro when: You want zero JS by default, need to mix UI frameworks, prefer an HTML-first approach, or are building blogs, docs, and marketing pages where interactivity is minimal.

Gatsby 5: Slice API

Gatsby 5 introduced the Slice API, allowing shared components (headers, footers, sidebars) to be built independently. When a navigation bar changes, only the slice rebuilds instead of every page that includes it.

// gatsby-node.js - Define slices
exports.createSlices = async ({ actions }) => {
  actions.createSlice({
    id: "header",
    component: require.resolve("./src/components/Header.js"),
  })
  actions.createSlice({
    id: "footer",
    component: require.resolve("./src/components/Footer.js"),
  })
}

// src/components/Layout.js - Use slices
import { Slice } from "gatsby"

export default function Layout({ children }) {
  return (
    <div>
      <Slice alias="header" />
      <main>{children}</main>
      <Slice alias="footer" />
    </div>
  )
}

Gatsby 5 also introduced Partial Hydration (beta), allowing you to mark components as server-only. Server components render at build time and ship zero JavaScript, similar to React Server Components in Next.js but using Gatsby's own implementation. This reduces the client-side bundle for pages that mix static and interactive content.

Common Gatsby Patterns

Sitemap and RSS Feed

// gatsby-config.js - Sitemap + RSS
module.exports = {
  siteMetadata: { siteUrl: "https://example.com" },
  plugins: [
    "gatsby-plugin-sitemap",
    {
      resolve: "gatsby-plugin-feed",
      options: {
        feeds: [{
          serialize: ({ query: { site, allMarkdownRemark } }) => {
            return allMarkdownRemark.nodes.map(node => ({
              title: node.frontmatter.title,
              date: node.frontmatter.date,
              description: node.excerpt,
              url: site.siteMetadata.siteUrl + "/blog/" + node.frontmatter.slug,
              custom_elements: [{ "content:encoded": node.html }],
            }))
          },
          query: `{
            allMarkdownRemark(sort: {frontmatter: {date: DESC}}) {
              nodes {
                excerpt
                html
                frontmatter { title, date, slug }
              }
            }
          }`,
          output: "/rss.xml",
          title: "My Blog RSS Feed",
        }],
      },
    },
  ],
}

Environment Variables

# .env.development
CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_token
GATSBY_API_URL=https://api.dev.example.com

# .env.production
CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_prod_token
GATSBY_API_URL=https://api.example.com

# Only GATSBY_ prefixed vars are available in client code.
# Non-prefixed vars only work in gatsby-config.js,
# gatsby-node.js, and gatsby-ssr.js.

TypeScript Support

Gatsby has built-in TypeScript support since version 4.8. You can use .tsx files for pages and components without additional configuration. Type generation for GraphQL queries is available through the graphql-typegen option.

// gatsby-config.ts (TypeScript config supported in Gatsby 5)
import type { GatsbyConfig } from "gatsby"

const config: GatsbyConfig = {
  // Enable automatic GraphQL type generation
  graphqlTypegen: true,
  siteMetadata: {
    title: "My TypeScript Gatsby Site",
    siteUrl: "https://example.com",
  },
  plugins: ["gatsby-plugin-image", "gatsby-plugin-sitemap"],
}

export default config

// src/pages/index.tsx - Type-safe page component
import React from "react"
import type { PageProps, HeadFC } from "gatsby"

const IndexPage: React.FC<PageProps> = ({ data }) => {
  return <h1>Hello TypeScript</h1>
}

export default IndexPage
export const Head: HeadFC = () => <title>Home</title>

Migration Paths

Whether you are migrating to Gatsby or considering moving away from it, understanding the key mapping points between frameworks saves significant effort.

WordPress to Gatsby (Headless)

  • Use gatsby-source-wordpress to pull content via the WordPress REST or WPGraphQL API
  • Keep WordPress as a headless CMS; serve the frontend through Gatsby
  • Map WordPress templates to Gatsby page templates in gatsby-node.js
  • Replace WordPress media with gatsby-plugin-image for automatic optimization
  • Migrate custom PHP functionality to React components or serverless functions

Gatsby to Next.js Migration Map

GatsbyNext.js Equivalent
gatsby-config.js pluginsnext.config.js + npm packages
GraphQL page queriesgetStaticProps / fetch in RSC
useStaticQuery hookDirect imports or fetch calls
gatsby-node.js createPagesgetStaticPaths + generateStaticParams
gatsby-plugin-imagenext/image component
Gatsby Head APImetadata export / Head component
gatsby-plugin-offlinenext-pwa or Serwist
DSG (defer: true)ISR (revalidate option)
Gatsby CloudVercel or Netlify

Frequently Asked Questions

What is Gatsby.js and what is it used for?

Gatsby.js is a React-based static site generator with a GraphQL data layer. It builds fast, SEO-friendly websites including blogs, marketing sites, e-commerce stores, and documentation by pre-rendering pages at build time into optimized static files.

How does Gatsby use GraphQL?

Gatsby has a built-in GraphQL schema that unifies all data sources. Source plugins pull data in at build time, and you query it using page queries (for pages) or the useStaticQuery hook (for any component).

What is the difference between SSG, SSR, and DSG?

SSG pre-renders all pages at build time (default). SSR generates pages per request for dynamic content. DSG defers building low-traffic pages until first request, then caches them as static HTML.

Is Gatsby still relevant in 2026?

Gatsby is solid for multi-source content sites. However, Next.js offers more flexibility for dynamic apps, and Astro delivers better performance for content sites. Choose based on your data sourcing needs and team expertise.

How do I optimize images in Gatsby?

Use gatsby-plugin-image with StaticImage (fixed paths) or GatsbyImage (dynamic GraphQL sources). It auto-generates responsive sizes, WebP/AVIF formats, lazy loading, and blur-up placeholders.

How does Gatsby compare to Next.js?

Gatsby has a built-in GraphQL data layer and rich plugin ecosystem for content sites. Next.js is a full-stack framework with SSR, ISR, and React Server Components for dynamic apps. They serve different primary use cases.

What are the best Gatsby plugins?

Essential ones: gatsby-source-filesystem, gatsby-transformer-remark, gatsby-plugin-image, gatsby-plugin-sharp, gatsby-plugin-sitemap, gatsby-plugin-manifest, and CMS source plugins (Contentful, Sanity, WordPress).

How do I deploy a Gatsby site?

Deploy static output to any host. Use Netlify (best Gatsby support after acquisition) or Vercel for SSR/DSG. AWS S3 + CloudFront, Cloudflare Pages, and GitHub Pages work for static-only sites.

Conclusion

Gatsby.js remains a capable static site generator with unique strengths in data aggregation and content management. Its GraphQL data layer provides a unified interface for pulling data from any source, and its plugin ecosystem offers pre-built solutions for common needs. SSR and DSG modes in Gatsby 4, along with the Slice API in Gatsby 5, addressed earlier limitations around build times and dynamic content.

The landscape has shifted: Next.js offers more versatility for full-stack applications, and Astro delivers better performance for content-driven sites. Choose Gatsby when your project benefits from its data layer, plugin ecosystem, and the unified React foundation it provides. For new projects, evaluate all three frameworks against your specific requirements.

𝕏 Twitterin LinkedIn
Var detta hjälpsamt?

Håll dig uppdaterad

Få veckovisa dev-tips och nya verktyg.

Ingen spam. Avsluta när som helst.

Try These Related Tools

{ }JSON FormatterJSON Validator

Related Articles

Nuxt 3: The Complete Guide to the Vue.js Full-Stack Framework

Master Nuxt 3 with file-based routing, server routes, composables, Nitro engine, auto-imports, modules, middleware, and deployment.

Deno: The Complete Guide to the Secure JavaScript Runtime

Master Deno runtime with security permissions, TypeScript support, standard library, HTTP server, testing, npm compatibility, and Deno Deploy.

esbuild: The Complete Guide to the Fastest JavaScript Bundler

Master esbuild for ultra-fast bundling with CLI, JavaScript API, plugins, loaders, minification, source maps, and production optimization.