How to Integrate Gatsby with Your Headless CMS
Connect Gatsby to structured content so every publish can rebuild the right pages, refresh previews, and ship fast static experiences without copying JSON by hand.
What is Gatsby?
Gatsby is an open-source React framework for building static sites, Deferred Static Generation pages, and server-rendered routes. It has a GraphQL data layer, an image pipeline, and a plugin system that teams use for marketing sites, documentation, ecommerce frontends, and campaign pages. Gatsby is especially common when you want fast page loads, Git-based builds, and content pulled from external APIs at build time.
Why integrate Gatsby with a headless CMS?
Gatsby works best when content is cleanly structured before the build starts. If your editors publish a product guide, case study, or landing page, Gatsby needs predictable fields like title, slug, heroImage, sections, author, and relatedLinks so it can create pages, generate images, and build its GraphQL schema without guesswork.
A headless CMS can provide that API layer, but the quality of the integration depends on how the content is modeled and how fast changes reach Gatsby. With Sanity's AI Content Operating System, content lives as typed JSON in the Content Lake. GROQ selects exactly the fields Gatsby needs, webhooks fire when content is published, updated, or deleted, and Functions can run server-side logic before a rebuild starts.
The alternative is usually slower and messier. Someone exports content to a file, pastes HTML into a repository, waits for a scheduled build, or writes one-off scripts that fetch too much data. That can work for a 12-page site. It gets painful when you have 1,000 product pages, localized routes, draft previews, and editors expecting changes to show up within minutes.
Architecture overview
A typical Gatsby integration starts in Sanity Studio, where editors publish structured documents such as posts, landing pages, products, and authors. Those documents are written to the Content Lake as typed JSON, including references between documents and assets. On publish, a Sanity webhook can trigger a Gatsby rebuild through your hosting provider's build hook, such as Netlify or Vercel. You can filter the webhook with GROQ so only relevant mutations trigger the build, for example posts, pages, or products with a defined slug. If you need extra logic, a Sanity Function can run on the content event, inspect the mutation, fetch related documents, and call the build hook without running a separate server. During the Gatsby build, Gatsby's Node APIs, such as sourceNodes and createPages, fetch content from Sanity with @sanity/client and GROQ. The query projects only what Gatsby needs, including joined references like author->name and category[]->slug.current. Gatsby turns that data into GraphQL nodes, creates routes from slugs, renders HTML, builds page-data JSON, and deploys the result to your CDN. End users get static pages, while editors get a publish flow that can trigger rebuilds automatically.
Common use cases
Marketing site rebuilds on publish
Publish a landing page in Sanity Studio, trigger a Gatsby rebuild through a build hook, and ship the updated static route to your CDN.
Documentation with structured navigation
Model docs, sidebars, release notes, and authors in Sanity, then let Gatsby generate section pages and nested routes from GROQ results.
Product content for static storefronts
Use Gatsby for fast product detail pages while Sanity keeps product stories, buying guides, SEO fields, and merchandising copy structured.
Localized campaign pages
Query locale-specific titles, slugs, Portable Text, and metadata so Gatsby can build /en, /fr, and /de routes from one content model.
Step-by-step integration
- 1
Create the Gatsby site and deployment target
Start a Gatsby project with npm create gatsby@latest or add Sanity to an existing Gatsby site. Gatsby itself doesn't require an account or API key. Your hosting provider does, so create a Netlify or Vercel project, add a build hook URL, and save it as GATSBY_BUILD_HOOK_URL.
- 2
Add Sanity credentials and client packages
Install the packages Gatsby will use to read content: npm install @sanity/client. Add SANITY_PROJECT_ID, SANITY_DATASET, and SANITY_API_VERSION to your environment. Use a read token only if Gatsby needs to read drafts or private datasets.
- 3
Model the content in Sanity Studio
Create schemas that match Gatsby routes, not just editor screens. For a blog, define post fields like title, slug, excerpt, mainImage, author reference, categories references, body, seoTitle, seoDescription, and publishedAt.
- 4
Source Sanity content into Gatsby
Use Gatsby's sourceNodes API or gatsby-source-sanity. With sourceNodes, fetch documents using GROQ, create Gatsby nodes with createNode, and then use createPages to generate routes from each slug.
- 5
Trigger builds from publish events
Create a Sanity webhook that fires on create, update, and delete for route-building document types. Point it at a webhook handler, a Sanity Function, or directly at your hosting build hook. If you need to inspect the changed document first, fetch it with GROQ before calling the build hook.
- 6
Test the full publish path
Publish a test document, confirm the webhook fires, verify that the hosting build starts, and check that Gatsby creates the expected page. Also test delete and slug-change cases, because those are where stale static pages most often appear.
Code example
This example shows the practical flow: a webhook handler receives a Sanity publish event, fetches the changed document with GROQ, and triggers a Gatsby rebuild. During the build, Gatsby uses its Node API to pull Sanity content into Gatsby nodes.
import {createClient} from '@sanity/client'
import type {VercelRequest, VercelResponse} from '@vercel/node'
import type {GatsbyNode} from 'gatsby'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-01-01',
useCdn: false,
})
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') return res.status(405).end()
const doc = await sanity.fetch(
'*[_id == $id][0]{_type,title,"slug":slug.current}',
{id: req.body._id}
)
if (!doc?.slug) return res.status(202).json({skipped: true})
await fetch(process.env.GATSBY_BUILD_HOOK_URL!, {method: 'POST'})
return res.status(200).json({queued: true, doc})
}
export const sourceNodes: GatsbyNode['sourceNodes'] = async ({actions, createNodeId, createContentDigest}) => {
const posts = await sanity.fetch(
'*[_type == "post" && defined(slug.current)]{_id,title,"slug":slug.current,excerpt,"author":author->name}'
)
posts.forEach((post: any) => {
actions.createNode({
...post,
id: createNodeId(`sanity-post-${post._id}`),
parent: null,
children: [],
internal: {type: 'SanityPost', contentDigest: createContentDigest(post)},
})
})
}How Sanity + Gatsby works
Build your Gatsby integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect Gatsby builds to the content your team publishes.
Start building free →CMS approaches to Gatsby
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Gatsby data shape | Often exposes rendered pages or plugin-specific exports, which can require HTML cleanup before Gatsby can build typed nodes. | Returns typed JSON from the Content Lake, with GROQ projections that match the exact Gatsby node shape you want. |
| Publish-to-build flow | May rely on manual rebuilds, scheduled jobs, or plugins that are tied to one hosting setup. | Uses GROQ-filtered webhooks and Functions so only relevant content changes call your Gatsby build hook. |
| Reference handling | Relationships are often page-centric, so Gatsby may need extra requests to connect authors, categories, and related content. | GROQ can join references in one query, such as author->name and categories[]->slug.current, before Gatsby creates nodes. |
| Preview and draft content | Preview often works inside the original system, but matching Gatsby's production routes can take custom plugin work. | Drafts can be queried with the right perspective and token, then used in Gatsby preview builds or a separate preview app. |
| Scale across channels | Works well when the website is the main output, but mobile apps and AI agents may need separate content paths. | Models your business as structured content, so Gatsby, mobile apps, commerce surfaces, and AI agents can read from one source. |
| Setup trade-off | Fast for simple brochure sites if editors are already trained in the system. | Requires schema design in code, but that gives Gatsby predictable content shapes, version control, and editor interfaces built for your workflow. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Vercel
Deploy Gatsby or Next.js frontends on Vercel and trigger builds from Sanity publish events.
Sanity + Netlify
Use Netlify build hooks with Sanity webhooks to rebuild Gatsby sites when content changes.
Sanity + Next.js
Pair Sanity with Next.js when you need static generation, server rendering, draft previews, and visual editing in one React app.