Skip to content
Gatsby Guide — React-Based Static Site Generator

Gatsby Guide — React-Based Static Site Generator

DodaTech Updated Jun 7, 2026 9 min read

Gatsby is a React-based static site generator that combines GraphQL data sourcing, powerful plugin architecture, and optimized build pipeline to create blazing-fast websites with excellent SEO, progressive image loading, and automatic performance optimization.

What You’ll Learn

You’ll understand Gatsby’s architecture, source and query data with GraphQL, create pages programmatically and with file-based routing, extend functionality with plugins and themes, optimize images with gatsby-plugin-image, and deploy with Gatsby Cloud.

Why Gatsby Matters

Gatsby pioneered the Jamstack architecture — pre-building HTML pages at compile time instead of rendering them on every request. This means your site loads instantly from CDN edge nodes with no server round-trip. Google’s research shows that sites loading in under one second have 3x higher conversion rates than those taking three seconds. DodaTech’s knowledge base uses Gatsby because its combination of React interactivity and static performance delivers both rich UX and instant load times.

Gatsby Architecture

    flowchart LR
  A[Data Sources] --> B[Gatsby Build]
  B --> C[GraphQL Data Layer]
  C --> D[React Components]
  D --> E[Static HTML Pages]
  E --> F[CDN Deployment]
  
  G[Plugins] --> B
  H[Themes] --> B
  I[gatsby-config] --> B
  
  B:::current
  
  classDef current fill:#663399,color:#fff,stroke:#333,stroke-width:2px
  
Prerequisites: Solid React fundamentals (components, JSX, props). Familiarity with GraphQL queries is helpful but not mandatory.

Project Structure

A typical Gatsby project follows this structure:

my-gatsby-site/
├── src/
│   ├── pages/          # File-based pages
│   │   ├── index.js
│   │   └── about.js
│   ├── components/     # Reusable components
│   ├── templates/      # Page templates for programmatic pages
│   └── images/         # Imported images
├── static/             # Raw static assets
├── gatsby-config.js    # Site configuration and plugins
├── gatsby-node.js      # Node API for programmatic page creation
└── gatsby-browser.js   # Browser API hooks

Data Layer with GraphQL

Gatsby sources data from multiple origins (filesystem, CMS, APIs) and unifies them into a single GraphQL layer:

// gatsby-config.js
module.exports = {
  siteMetadata: {
    title: 'DodaTech Tutorials',
    description: 'Learn programming and security',
    siteUrl: 'https://dodatech.com'
  },
  plugins: [
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'content',
        path: `${__dirname}/content/`
      }
    },
    'gatsby-transformer-remark', // Transforms .md files to HTML
    'gatsby-plugin-image',
    'gatsby-plugin-sharp',
    'gatsby-transformer-sharp'
  ]
};

Query data in any component using Gatsby’s useStaticQuery hook or page query:

import { graphql, useStaticQuery } from 'gatsby';
import { GatsbyImage } from 'gatsby-plugin-image';

function HeroSection() {
  const data = useStaticQuery(graphql`
    query {
      site {
        siteMetadata {
          title
          description
        }
      }
      heroImage: file(relativePath: { eq: "hero.jpg" }) {
        childImageSharp {
          gatsbyImageData(
            width: 1200
            placeholder: BLURRED
            formats: [WEBP, AVIF]
          )
        }
      }
    }
  `);

  return (
    <section>
      <h1>{data.site.siteMetadata.title}</h1>
      <p>{data.site.siteMetadata.description}</p>
      <GatsbyImage
        image={data.heroImage.childImageSharp.gatsbyImageData}
        alt="Hero banner"
        loading="lazy"
      />
    </section>
  );
}

Output: At build time, Gatsby fetches the site metadata and hero image from GraphQL, generates an optimized WebP/AVIF image with a blurred placeholder, and renders the hero section with the pre-built HTML. No client-side data fetching is needed.

File-Based Pages and Programmatic Pages

File-Based Pages

Pages in src/pages/ become routes automatically:

// src/pages/about.js
import React from 'react';
import { graphql } from 'gatsby';

export default function AboutPage({ data }) {
  return (
    <main>
      <h1>{data.markdownRemark.frontmatter.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: data.markdownRemark.html }} />
    </main>
  );
}

// Page query — runs at build time
export const query = graphql`
  query ($id: String) {
    markdownRemark(id: { eq: $id }) {
      frontmatter { title }
      html
    }
  }
`;

Programmatic Pages with gatsby-node.js

For dynamic content like blog posts, create pages programmatically:

// gatsby-node.js
const path = require('path');

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;
  
  // Query all blog posts
  const result = await graphql(`
    query {
      allMarkdownRemark(filter: { frontmatter: { type: { eq: "post" } } }) {
        nodes {
          id
          frontmatter {
            slug
            title
          }
        }
      }
    }
  `);
  
  // Create a page for each post
  result.data.allMarkdownRemark.nodes.forEach((node) => {
    createPage({
      path: `/blog/${node.frontmatter.slug}/`,
      component: path.resolve('./src/templates/blog-post.js'),
      context: {
        id: node.id
      }
    });
  });
};
// src/templates/blog-post.js
import React from 'react';
import { graphql } from 'gatsby';

export default function BlogPost({ data }) {
  const post = data.markdownRemark;
  
  return (
    <article>
      <h1>{post.frontmatter.title}</h1>
      <time>{post.frontmatter.date}</time>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </article>
  );
}

export const query = graphql`
  query ($id: String) {
    markdownRemark(id: { eq: $id }) {
      frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
      }
      html
    }
  }
`;

Output: During gatsby build, the script queries all markdown posts, creates a unique URL for each one (e.g., /blog/hello-world/), and generates a static HTML file for each post. The GraphQL query in the template fetches the specific post’s data using the id passed from context.

Image Optimization with gatsby-plugin-image

Gatsby’s image plugin generates multiple sizes and formats automatically:

import { GatsbyImage, getImage } from 'gatsby-plugin-image';

function ProductCard({ product }) {
  const image = getImage(product.image);
  
  return (
    <div className="product-card">
      <GatsbyImage
        image={image}
        alt={product.name}
        loading="lazy"
        className="product-image"
      />
      <h3>{product.name}</h3>
      <p>${product.price}</p>
    </div>
  );
}

Output: The plugin generates WebP, AVIF, and JPEG versions of the image at multiple widths (320px, 640px, 960px, 1280px). The browser downloads the smallest appropriate format. A blurred placeholder shows while loading. The image lazy-loads below the fold. All of this happens automatically — no manual image handling is needed.

Plugins and Themes

Source Plugins

Source plugins pull data from external services:

// gatsby-config.js
plugins: [
  {
    resolve: 'gatsby-source-contentful',
    options: {
      spaceId: process.env.CONTENTFUL_SPACE_ID,
      accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
    }
  },
  {
    resolve: 'gatsby-source-wordpress',
    options: {
      url: 'https://example.com/graphql'
    }
  },
  'gatsby-source-strapi'
]

Transformer Plugins

Transformer plugins convert source data into queryable nodes:

// Example: Markdown files become queryable HTML nodes
// gatsby-transformer-remark + gatsby-source-filesystem
// Enables this query:
// query { allMarkdownRemark { nodes { html frontmatter { title } } } }

Themes

Themes bundle config, components, and data sourcing into reusable packages:

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: 'gatsby-theme-blog',
      options: {
        basePath: '/blog',
        contentPath: 'content/posts'
      }
    },
    {
      resolve: 'gatsby-theme-docs',
      options: {
        basePath: '/docs'
      }
    }
  ]
};

Output: Themes provide pre-built functionality (blog layouts, documentation navigation) that you can customize through shadowing — placing a file in the same path as the theme’s file overrides it. This gives you production-ready features with minimal code.

Building and Deploying

# Development
gatsby develop
# Starts dev server at localhost:8000 with hot reload

# Production build
gatsby build
# Output: public/ — static HTML, JS, CSS, images

# Serve built site locally
gatsby serve
# Starts production build at localhost:9000

Deployment to Gatsby Cloud

Gatsby Cloud provides automatic builds, incremental builds, and preview deployments:

1. Connect your Git repository to Gatsby Cloud
2. Configure build environment variables
3. Enable Content Sync for CMS previews
4. Set up branch-based preview deployments
5. Deploy to the built-in CDN or connect a custom domain

Security Angle: Build-Time Data Validation

// gatsby-node.js — Validate all Markdown pages at build time
exports.createPages = async ({ graphql, actions }) => {
  const result = await graphql(`
    query {
      allMarkdownRemark {
        nodes {
          frontmatter {
            title
            slug
            date
            author
          }
          fileAbsolutePath
        }
      }
    }
  `);

  const errors = [];
  
  result.data.allMarkdownRemark.nodes.forEach((node) => {
    if (!node.frontmatter.title) {
      errors.push(`Missing title in ${node.fileAbsolutePath}`);
    }
    if (!node.frontmatter.slug) {
      errors.push(`Missing slug in ${node.fileAbsolutePath}`);
    }
    if (node.frontmatter.slug && node.frontmatter.slug.includes(' ')) {
      errors.push(`Slug contains spaces in ${node.fileAbsolutePath}`);
    }
  });
  
  if (errors.length > 0) {
    console.error('Build errors found:');
    errors.forEach(e => console.error(`  - ${e}`));
    process.exit(1); // Fail the build
  }
  
  // Continue with page creation
};

This pattern catches content errors before deployment, preventing broken pages on the live site. DodaTech’s documentation pipeline uses similar validation to ensure every tutorial has the required frontmatter fields before publishing.

Common Mistakes Beginners Make

  1. Forgetting to restart gatsby develop after config changes: gatsby-config.js and gatsby-node.js changes require restarting the dev server. Save-and-reload doesn’t pick them up.

  2. Querying non-existent fields: GraphQL queries that request fields not present in the schema fail the build. Always check the GraphiQL explorer at localhost:8000/___graphql for available fields.

  3. Missing alt text on GatsbyImage: The alt prop is required. Forgetting it causes accessibility violations and may fail build-time checks.

  4. Using client-side data fetching unnecessarily: Gatsby’s strength is build-time data sourcing. Using useEffect + fetch to load data that could come from GraphQL defeats the purpose of static generation.

  5. Ignoring the public/ directory size: Large images and excessive pages can make public/ gigabytes in size. Audit generated HTML and optimize aggressively.

  6. Not configuring path prefix for subdirectory deployment: Deploying to https://example.com/blog/ requires pathPrefix: '/blog' in gatsby-config.js.

Practice Questions

  1. What is the difference between a page query and useStaticQuery?
  2. How do you create pages dynamically from Markdown files?
  3. What does gatsby-plugin-image do automatically?
  4. What happens if a GraphQL query fails during build?
  5. Why might you choose Gatsby over a plain React app?

Answers:

  1. Page queries are available only in top-level page components (src/pages/ and templates) and support variables. useStaticQuery works in any component but doesn’t support variables.
  2. Use gatsby-node.js’s createPages API to query Markdown files, iterate over them, and call createPage for each one with a template component and context.
  3. It generates multiple sizes, formats (WebP, AVIF), blurred placeholders, lazy loading, and responsive srcsets automatically.
  4. The build fails with an error message showing the query and the missing field. This prevents deploying broken pages.
  5. Gatsby pre-builds HTML at compile time, resulting in instant page loads from CDN, better SEO (full HTML on first response), and lower server costs.

Challenge

Build a documentation site with Gatsby: source content from Markdown files, create pages for each document using gatsby-node.js, add a sidebar navigation component that queries the page structure, enable search with client-side indexing, and deploy with Gatsby Cloud.

Real-World Task

Create a portfolio site that sources project data from Markdown files, uses gatsby-plugin-image for project screenshots, includes a tag-based filtering system, and implements a contact form that posts to a serverless function.

FAQ

What is the difference between Gatsby and Next.js?
: Gatsby is primarily a static site generator with build-time data sourcing. Next.js supports SSR, SSG, and ISR (incremental static regeneration). Gatsby has a richer plugin ecosystem; Next.js has broader rendering flexibility.
Does Gatsby support dynamic content?
: Yes, through client-side data fetching, serverless functions (Gatsby Functions), and Content Sync for CMS previews. However, Gatsby is optimized for content-heavy sites where most pages are pre-built.
Can I use Gatsby with a headless CMS?
: Yes. Gatsby has source plugins for Contentful, WordPress, Strapi, Sanity, DatoCMS, and dozens more. The CMS data is fetched at build time and baked into the static pages.
How do I handle forms in Gatsby?
: Use Gatsby Functions (serverless endpoints) for form handling, or integrate with form services like Formspree, Netlify Forms, or Google Forms.
Is Gatsby free?
: Yes, Gatsby is open source. Gatsby Cloud has a free tier for personal projects and paid tiers for teams with features like incremental builds and Content Sync.

Try It Yourself

# Create a new Gatsby site
npm init gatsby
cd my-gatsby-site
# Select "Add Markdown Blog" from the starter wizard
gatsby develop

Add a new Markdown file to content/posts/ with frontmatter including title, date, slug, and tags. Create a tag archive page that lists posts grouped by tag using a page query.

What’s Next

Related topics: React, GraphQL, JavaScript, Node.js

What’s Next

Congratulations on completing this Gatsby tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro