How to integrate Contentful with Gatsby for fast static site generation

If you’re building a static site and want to pull in dynamic content, the Gatsby + Contentful combo gets thrown around a lot. But getting them to play nicely isn’t always plug-and-play—especially if you want sites that are both fast and easy to update. This guide is for developers who want straight talk about setting up Contentful as a headless CMS with Gatsby, without getting bogged down in hype or unnecessary complexity.


Why Gatsby + Contentful? (And When It’s Overkill)

Gatsby is great for static sites: it’s fast, SEO-friendly, and has a huge plugin ecosystem. Contentful, meanwhile, is a cloud-based CMS with a slick UI and a decent free tier. Together, they let you build sites where non-tech folks can edit content, and developers can ship blazing-fast static pages.

But: If you’re building a tiny site with content that rarely changes, you might not need Contentful—or Gatsby, for that matter. Sometimes plain Markdown files or even a single HTML file will do the job. Use these tools when:

  • You want non-developers to update content easily.
  • Your site has more than a handful of pages or complex content types.
  • You care about performance and SEO.

Still onboard? Let’s get to it.


Step 1: Set Up Your Contentful Space

First, sign up for a Contentful account if you don’t have one. Their free plan is fine for getting started.

Create a new "Space": - This is basically your content workspace. Give it a name.

Define Content Models: - Think of content models as “templates” for your data. For a blog, you might need a Post model with fields like title, slug, publishDate, and body. - Don’t overthink the structure here. You can always tweak it later.

Add Some Content: - Create a few entries so you’ve got data to pull into Gatsby. If you skip this, Gatsby queries will just return empty results and you’ll be scratching your head.

Pro tip: Use short, lowercase API IDs for your fields (e.g., body, not BlogPostMainContent). It’ll keep your GraphQL queries less painful later.


Step 2: Set Up Your Gatsby Project

If you don’t have Gatsby installed:

bash npm install -g gatsby-cli

Create a new project:

bash gatsby new my-gatsby-contentful-site cd my-gatsby-contentful-site

You now have the basic Gatsby skeleton.


Step 3: Install the Contentful Source Plugin

This is the bridge between Gatsby and Contentful.

bash npm install gatsby-source-contentful

You’ll need two things from Contentful: - Space ID: Find this in the Contentful web app under Settings → Space Settings. - Content Delivery API Access Token: Go to Settings → API Keys, create one, and copy the token.


Step 4: Configure gatsby-config.js

Open up gatsby-config.js and add the plugin configuration:

js require("dotenv").config();

module.exports = { plugins: [ { resolve: gatsby-source-contentful, options: { spaceId: process.env.CONTENTFUL_SPACE_ID, accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, }, }, // ...other plugins ], };

Why the .env?
Don’t hard-code API keys in config files. Create a .env file in your project root:

CONTENTFUL_SPACE_ID=your_space_id_here CONTENTFUL_ACCESS_TOKEN=your_access_token_here

Add .env to your .gitignore so you don’t accidentally leak credentials.


Step 5: Fetch and Explore Content with GraphQL

Gatsby pulls in Contentful data at build time and exposes it via GraphQL. Start the development server:

bash gatsby develop

Go to http://localhost:8000/___graphql. Here you can run queries against your Contentful data.

Example Query:

graphql { allContentfulPost { nodes { title slug publishDate(formatString: "YYYY-MM-DD") body { raw } } } }

If you don’t see your content types, double-check your Contentful space and entries. Sometimes it takes a minute for new content models to show up after a fresh build.


Step 6: Create Pages Dynamically from Contentful Data

Time for the real power move: auto-generating pages from your Contentful entries.

Basic idea:
- Use Gatsby’s Node API (gatsby-node.js) to query for all entries. - For each entry, create a page using a template.

Here’s a minimal gatsby-node.js example:

js const path = require('path');

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

const result = await graphql({ allContentfulPost { nodes { slug } } });

if (result.errors) throw result.errors;

result.data.allContentfulPost.nodes.forEach((node) => { createPage({ path: /blog/${node.slug}/, component: blogPostTemplate, context: { slug: node.slug, }, }); }); };

What’s happening? - For each Contentful post, Gatsby creates a /blog/slug/ page. - The context object lets your template know which post to fetch.


Step 7: Build a Template to Render Contentful Data

Create a file at src/templates/blog-post.js:

js import React from "react"; import { graphql } from "gatsby";

export default function BlogPost({ data }) { const post = data.contentfulPost; return (

{post.title}

{post.publishDate}

); }

export const query = graphqlquery($slug: String!) { contentfulPost(slug: { eq: $slug }) { title publishDate(formatString: "MMMM D, YYYY") body { childMarkdownRemark { html } } } };

Note:
- If you use Contentful’s “Rich Text” field, you’ll need to use their rich text renderer instead of dangerouslySetInnerHTML. - If you use plain “Text” fields, you may need to process Markdown (the plugin can help). - Don’t get tripped up by field names—double-check them in GraphiQL.


Step 8: Build and Deploy

Run a production build:

bash gatsby build

Check the public/ folder—these are your static files, ready to deploy anywhere (Netlify, Vercel, S3, whatever).

Deploying:
Pick your favorite static hosting. Netlify and Vercel both have dead-simple Git-based deploys. No need to overthink this.


Gotchas, Annoyances, and Honest Advice

  • Content Model Changes:
    Renaming or deleting fields in Contentful can break your build. If you change things, re-run gatsby develop and check your queries.
  • Build Times:
    Gatsby sites with a lot of Contentful entries can get slow to build. If you’re pushing thousands of pages, consider Gatsby Cloud or incremental builds, but don’t use pricey services if you don’t need them.
  • Previewing Content:
    Contentful drafts won’t show up in Gatsby unless you use the Preview API and a different plugin setup. For most static sites, this isn’t a dealbreaker, but it’s worth knowing.
  • Rich Text Fields:
    Contentful’s rich text is… quirky. You’ll probably need their @contentful/rich-text-react-renderer package to display it nicely.
  • Watch Your API Limits:
    Contentful’s free tier has generous limits, but if you’re hammering the API for previews or builds, you can hit walls. Most personal sites never run into this.

Should You Use Contentful with Gatsby for Every Project?

No. If your site is small, doesn’t change much, or you’re the only one updating content, simpler setups (like Markdown or JSON) are easier to manage and a lot less fragile. But if you want a fast site that non-devs can update, this combo is solid—and once you’ve got the plumbing done, it’ll save time in the long run.


Final Thoughts: Keep It Simple, Iterate Often

Don’t spend days obsessing over the “perfect” content model or Gatsby plugin setup. Get something working, then tweak as you need. Most problems show up only after you’ve shipped and started using the site. Contentful and Gatsby are both flexible, but it’s easy to overcomplicate things chasing the “best” solution. Start simple, iterate, and only add complexity when it actually solves a real problem.

Now go build something fast—and don’t forget to write things down as you go. Future you will thank you.