Learn Gatsby - Architecture & Design Patterns
Series/Learn Gatsby/Episode 18
Episode 18 of 24

Learn Gatsby - Architecture & Design Patterns

This episode covers architecture and design patterns for Gatsby: a scalable project structure, component-driven design and content modeling, patterns for shared components, hooks, and utilities, and strategies for maintainability and collaboration.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

As a site grows, good architecture becomes more valuable than new features. Decisions about folder structure, how to split components, and how to share code determine whether a project stays easy for new team members to understand.

Episode 18 covers a scalable Gatsby project structure, component-driven design and content modeling, patterns for shared components, hooks, and utilities, and strategies for maintainability and collaboration.

Project Structure for a Scalable Site

Organizing by Domain

The src folder should be grouped by function rather than merely by file type. The following structure separates pages, templates, components, and hooks with clear responsibilities:

src folder structure
src/
  pages/
  templates/
  components/
    layout/
    ui/
  hooks/
  utils/
  data/
  styles/

src/pages holds file-based routing, src/templates holds templates for pages created programmatically via createPage, while src/components holds reusable components.

For large projects, the components folder can be split further per feature — for example, components/blog/ and components/checkout/. Feature-based separation keeps code that changes together together, so teams working on different features rarely collide on the same files. This structure also makes code review easier: changes in one feature are clearly visible without touching another feature's folders.

Put files that change together side by side: a component's styles, tests, and hooks live in that component's folder. Colocation shortens the search distance and makes each component a self-contained unit. When a component is deleted, all its dependents go with it without leaving floating artifacts. A simple rule: if two files always change together, keep them adjacent.

Component-Driven Design and Content Modeling

Component Composition

Design components from small pieces, then assemble them into larger ones. Pages are built from sections, sections from cards, and cards from presentational elements. This consistency lets a design change be made at just one level. An overly large component signals a missing composition layer — break it into smaller parts with single responsibilities.

Content Modeling

The content types in your data model should match what the pages need. When defining the GraphQL schema in Gatsby, pull commonly used fields up to the same level so template queries stay simple and don't duplicate transformation logic. A good content model is a predictable one: anyone reading the schema immediately understands what data is available without guessing. Changing a model in the CMS costs more than changing a component, so think carefully before adding a new field. Start with the smallest model that satisfies the pages, then grow it when the need genuinely appears.

Shared Components, Hooks, and Utility Patterns

Custom Hooks for Recurring Logic

Logic used by many components — reading site metadata, accessing query data — moves into a custom hook. Here's an example of reading site metadata:

JSuseSiteMetadata hook
import { useStaticQuery, graphql } from "gatsby"
 
export const useSiteMetadata = () => {
  const data = useStaticQuery(graphql`
    query SiteMetadata {
      site {
        siteMetadata {
          title
          description
        }
      }
    }
  `)
 
  return data.site.siteMetadata
}

useSiteMetadata wraps the useStaticQuery query so consumer components just call one hook instead of writing the query repeatedly. The use naming convention is mandatory so React recognizes the hook and applies the rules of hooks correctly.

Hooks can be tested like plain functions — wrap them in a small component and assert the result. This pattern keeps React's rules satisfied while ensuring the logic stays correct. Put hook tests in the same folder as the hook so they stay colocated and easy to find.

Pure Utility Functions

Data transformation functions — date formatting, slug generation, filtering — are separated into src/utils as pure functions. Pure functions are easy to test because they take input and return output without side effects. If a function starts reading localStorage or writing to the DOM, move that responsibility into a hook or component. Use descriptive function names so their usage is predictable without reading the implementation.

Maintainability and Collaboration

Conventions and Typing

Establish naming conventions for components, event handlers, and CSS before the team starts writing code. Using TypeScript adds a safety layer: misspelled props get caught at compile time rather than runtime. Document architecture decisions in a short README so new team members don't have to guess.

Also agree on team tooling — formatter, linter, and test runner — and commit the configuration to the repository. That way every team member gets the same behavior without manual setup. Agreed configuration also reduces noise in pull requests that should focus on the logic of the change.

Documentation and Onboarding

Include a README explaining how to run the project, the folder structure, and the conventions in force. Good documentation speeds up onboarding for new team members and reduces repeated Q&A. Update documentation in the pull requests that change the workflow, rather than putting it off until the end of the sprint. Keep documentation short and focused on what's frequently asked.

Continuous Review and Refactoring

Keep a habit of small refactors whenever you add a feature, rather than waiting for technical debt to pile up. Small, focused pull requests are easier to review and produce fewer conflicts than giant changes. Make refactoring part of the definition of done, not a separate task that always gets postponed.

Conclusion

Key takeaways:

  • Group the src folders by function and domain.
  • Colocate styles, tests, and hooks with their components.
  • Assemble pages through component composition from small to large.
  • Custom hooks encapsulate queries and logic used repeatedly.
  • Pure functions in src/utils are easy to test.
  • Small refactors and regular reviews keep code quality high.

In the next episode, episode 19, we'll discuss modern tooling and build automation — the Gatsby CLI, TypeScript support, CI/CD pipelines, and linting, formatting, and pre-commit hooks.