August 13, 2020

Running Gatsby.js Sites with Craft CMS

If you're interested in a more general post about the value of a simpler tech stack, check out "Keep your stack short".

We recently developed and launched a couple Gatsby.js websites at TrendyMinds that are sourced by Craft CMS as the back-end. Because this is a relatively new way to build websites I wanted to discuss some technical learnings from this pairing.

I won't get into the general "pros" of Gatsby.js. There are much better articles explaining why you might utilize a static site generator and the benefits they yield.

Instead, I'll be focusing more on what it was like using Craft CMS and Gatsby.js together.

Front-end unification

One of the best, most immediate advantages of Gatsby.js is the opinionated front-end and first-class support for React components.

When developing a Craft CMS website your templating is done server-side using Twig and it's common to "sprinkle in" JavaScript. For instance, adding a React component might be handled by creating an HTML entrypoint:

<div data-modal></div>

Then inject your React component:

import { render } from "react-dom";

  <Modal />,

And, while this does allow you to utilize React within your Craft CMS templates, it lacks interoperability and you effectively "hand off" templating responsibilities between two parties.

Instead, Gatsby.js provides the ability to unite the front-end under React:

import Modal from "./components/Modal";

export default function About() {
  return (
      <h1>The About Page</h1>
      <Modal />

Larger debugging surface

Gatsby.js has an immediate effect on site speed and gives developers the benefit of using React everywhere and GraphQL queries. However, the additions of these layers increases where you might run into bugs.

If you're using Craft for your back-end and front-end the scope of problems is much smaller. It's limited to a reduced stack.

Consider the following architecture.

A standard Craft CMS stack

Craft Data

A Gatsby.js site sourced by Craft
Craft Data
Gatsby GraphQL

Our standard Craft CMS stack—while modest and lacking the benefits of separating your back-end and front-end—is simple.

The shorter stack allows for the scope of bugs to also remain shallow.

However, in our Gatsby.js and Craft CMS stack we've expanded the surface area where bugs may lurk.

On scaling

It's worth noting that there can be a benefit in this level of separation.

You might find separating the front-end and the back-end is better because you now have the ability to scale the environments separately and prevent back-end outages from affecting your front-end.

This gives you more flexibility than the shorter, less sophisticated stack. But you'll need to calculate the cost of taking the bad as well as the good.


Maybe you're considering Gatsby.js because you primarily want performance and better interoperability between templates and reactive JavaScript.

If that's you, I might recommend a combination of:

  • Blitz: The wonderful full-page static caching plugin by Ben Croker that everyone should be using
  • Alpine.js: A fantastic, build tool-less, reactive, ~8kB 😱 library that let's you handle reactive UI in your Twig templates
  • Sprig: A Livewire-inspired plugin to create complex views using AJAX and Twig templates (also by Ben Croker; what can't this guy do?)

I think the three of these tools are well-built, designed for performance, and have fantastic interoperability with the server-side rendered templates that Craft CMS provides natively.

This helps eliminate the overhead of solving Gatsby.js problems like Live Preview, incremental builds, running server-side code without reaching for serverless functions (further increasing your stack). And it grants your server-rendered site the performance and (some of the) templating benefits of Gatsby.js.

Closing thoughts

None of this is to dissuade you from using Gatsby.js and Craft CMS together.

In fact, you might be on the brink of a project that is perfectly suited for this setup and the separation of the front-end and the back-end is icing on the cake.

However, it's worth considering if this—along with all programming choices—strikes the right balance of cost and complexity.