Gatsby Minimum Viable Build with Sanity CMS
Tags: webdev, gatsby, jamstack, tutorial
Published: 2020-07-09 16:13:59

---
title: Gatsby Minimum Viable Build with Sanity CMS
description:  "Continuing from my minimum viable build"
published: true
date: 2020-07-08 15:00:00 UTC
tags: webdev,gatsby,jamstack,tutorial
series: Playing With Gatsby
cover_image: https://katiekodes.com/images/header-gatsby-sanity-202007.png
canonical_url: https://katiekodes.com/gatsby-sanity-hello/
---

Recap: [a directory only needs two small files in it for the Gatsby static website generator to turn it into a functioning `index.html`](https://dev.to/katiekodes/gatsby-minimum-viable-build-3n13) with a body of `<div>Hello world!</div>`, and it only needs [five or six to use an `index.md` file as the source of the “Hello World” text](https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26).  
  
Now, instead of pulling `Hello World` from a file within my project, I’ll make Gatsby’s build process download it from a 3rd-party API attached to a great little content management system called [Sanity](https://sanity.io).  
  
Properly configured, Sanity looks beautiful for non-technical content editors, and paired with Gatsby Cloud’s “preview” sites, content authors can literally watch a preview of their site change as they type – all while getting the performance and security benefits of a static production web site.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/65-live-editing-animated.gif)

## Desired output

I’m still just shooting for some variation on this HTML for the contents of `index.html`:

```html
<html>
	<head></head>
	<body>
		<div>Hello World</div>
	</body>
</html>

```

## Sanity CMS

In my previous post, [Sanity CMS Minimum Viable Build](https://dev.to/katiekodes/sanity-cms-minimum-viable-build-4e2f-temp-slug-7151350), I set up a lovely content management system that looks like this for a content author:

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/40-sanity-publish-an-xyzzy.png)

Sanity generates output something like this over an API that a Gatsby plugin can connect to as a data source:

```json
{
	"message":"Hello World",
	"slug":{
		"current":"/"
	},
	"template":"xyzzy"
}

```

* * *

## Files

Pick a folder on your hard drive that will serve as your local copy of all the Gatsby-related files you need to put into your git repository on GitHub.

I chose `C:\example\mysite_gatsby`.

Fill this folder with the following 4 files, which you can see an example of [on GitHub here](https://github.com/kkgthb/web-site-gatsby-05-template-sanity-gatsbyhalf).

```
.
├── src
│ └── templates
│ └── xyzzy.js
├── gatsby-config.js
├── gatsby-node.js
└── package.json

```

* * *

### `/package.json`

As in the rest of this series I have to specify that certain [Node](https://en.wikipedia.org/wiki/Node.js) packages like React and like Gatsby itself are essential to building the static site. I’ll also specify one Gatsby plugin called `gatsby-source-sanity` that I’ll need:

You, of course, don’t need to set your `name`, `description`, `version`, etc. the same as I set mine.

```json
{
	"name" : "netlify-gatsby-test-05",
	"description" : "Does this really work?",
	"version" : "0.0.5",
	"scripts" : {
		"develop": "gatsby develop",
		"start": "npm run develop",
		"build": "gatsby build",
		"serve": "gatsby serve"
	},
	"dependencies" : {
		"gatsby": ">=2.22.15",
		"gatsby-source-sanity": ">=6.0.1",
		"react": ">=16.12.0",
		"react-dom": ">=16.12.0"
	}
}

```

* * *

### `/gatsby-config.js`

I need to “activate” the Gatsby plugin `gatsby-source-sanity` with a file called `gatsby-config.js`:

```javascript
module.exports = {
    plugins: [
		{
			resolve: "gatsby-source-sanity",
			options: {
				projectId: "your-sanity-project-id",
				dataset: "your-sanity-dataset-name",
				...(process.env.SANITY_READ_TOKEN && { token: process.env.SANITY_READ_TOKEN }),
				...(process.env.SANITY_WATCH_MODE && process.env.SANITY_READ_TOKEN && { watchMode: process.env.SANITY_WATCH_MODE }),
				...(process.env.SANITY_OVERLAY_DRAFTS && process.env.SANITY_READ_TOKEN && { overlayDrafts: process.env.SANITY_OVERLAY_DRAFTS }),
			}
		}
    ]
};

```

In the [options](https://github.com/sanity-io/gatsby-source-sanity#options) part of this code…

- Replace `your-sanity-project-id` in this code with your actual Sanity project ID.      
  - _([Mine]https://katiekodes.com/sanity-minimum-viable-build/#look-around-the-project){:target=”\_blank”} starts with a “z” and ends with an “m”)_.
- Replace `your-sanity-dataset-name` with your actual Sanity project’s dataset’s name.      
  - _(Mine is `top_secret_stuff`)_.

In case you’re curious, the `...( some-boolean-condition && some-javascript-object)` syntax is a nifty [ES6 trick for setting properties of a JavaScript object only under certain conditions](https://www.kevinpeters.net/adding-object-properties-conditionally-with-es-6).

I’m using it to make sure I only set the `token`, `watchMode`, and `overlayDrafts` properties of the `options` object if certain “environment variables” are set in my host environment _(e.g. Netlify or Gatsby Cloud)_.

Otherwise, this configuration file treats the [options](https://github.com/sanity-io/gatsby-source-sanity#options) object as only having `projectId` and `dataSet` properties.

* * *

### `/src/templates/xyzzy.js`

I'm using a standalone `Xyzzy` **React component** as a "template" for rendering my home page, just like in my ["minimum viable" Markdown-based Gatsby project](https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26#-raw-srctemplatesxyzzyjs-endraw-).

I'll dynamically fetch the text "`Hello World`" from `/src/pages/index.md` as a detail of `pageContext` called `pageContext.message` _(or, if I had been using classes, `this.props.pageContext.message`)_.

Note that the "`message`" property of `pageContext` doesn't exist yet.  I'll soon write code in a file called `gastby-node.js` that makes Gatsby include `message` in `pageContext`.

For now, trust that `{pageContext.message}` is the equivalent of `Hello World` -- I'll use `gatsby-node.js` next to get it from Sanity into `pageContext`.

```javascript
import React from "react"

export default function Xyzzy({ pageContext }) {
  return (
    <div>
	  {pageContext.message}
    </div>
  )
}

```

> Note:  If you've followed the [Markdown-based variation of this project](https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26#-raw-srctemplatesxyzzyjs-endraw-), you might notice that I flipped from using `{pageContext.frontmatter.message}` to `{pageContext.message}`.
> 
> {% link https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26 %}
> 
> That's a quirk of the way my data flows out of various plugins for fetching data available for Gatsby to turn into pages.
> 
> I won't cover how to do it, but if I'd built up a massive theme of templates and components using Markdown and referring to `pageContext.frontmatter.message`, it might have been nice to write clever code in `gatsby-node.js` that put a meaningless `frontmatter` property in between `pageContext` and `message` when switching to Sanity, just to avoid re-writing all my templates.
> 
> On the other hand, there are probably better ways to write Gatsby templates and queries for page data and templates so as to avoid this problem in the first place!  Remember, I'm new around here.  :)

* * *

### `/gatsby-node.js`

Last but not least, we have the file that teaches Gatsby how to put everything together: `gatsby-node.js`.

```javascript
const path = require(`path`)

exports.createPages = async ({ graphql, getNode, actions }) => {
  const { createPage } = actions
  const queryResult = await graphql(`
    query {
      allSanityXyzzy(filter: {slug: {current: {ne: null}}}) {
          edges {
            node {
              template,
              message,
              slug {
                current
              }
            }
          }
      }
    }
  `)
  nodes = queryResult.data.allSanityXyzzy.edges
  nodes.forEach(({ node }) => {
    createPage({
      path: node.slug.current,
      component: path.resolve(`./src/templates/${node.template}.js`),
      context: {
        message: node.message,
      },
    })
  })
};

```

#### No `onCreateNode` override

In this case, we don’t need to override `onCreateNode()`. We can do everything in our override of `createPages()`.

#### Overriding `createPages`

Earlier, I said that I would need to teach Gatsby to pass details queried from Sanity’s API to to `xyzzy.js` as a `frontmatter` sub-property of a Gatsby concept called `pageContext`.

I do this and more by overriding Gatsby’s definition of a Gatsby function called `createPages()` within a file called `gatsby-node.js` placed in the root directory of my folder structure.

The first thing I do is tell Gatsby to make a **GraphQL** query against its entire **self-inventory** of **stuff it knows about** and likes to call “nodes” _(not to be confused with [Node](https://en.wikipedia.org/wiki/Node.js) for which Gatsby is a package)_, filtering to only return the ones that seem to be “SanityXyzzy” data points \_(that is, pieces of data that into Sanity Studio as [`X y zz y`-typed data](https://katiekodes.com/sanity-minimum-viable-build/#schemasxyzzyjs) objects, and save the resulting JavaScript object into a variable I decided to call `queryResult`.

Comparing this code to [`gastby-node.js` for my Markdown-based “Hello World”](https://katiekodes.com/gatsby-hello-world-variations/#gatsby-nodejs), you might notice that I literally just have to switch from looking for `allMarkdownRemark` to `allSanityXyzzy`.

Three cheers for smart developers writing Gatsby and its plugin ecosystem so we don’t have to think about _why_ this works like magic!

The part of `queryResult` that I’m interested in is an array of “`node`” objects accessible through `queryResult.data.allSanityXyzzy.edges` – I’ll set that array aside into a variabled called `nodes`.

_(In my case, there’s only one object in the `nodes` array: the one whose `message` I set to `Hello World` over in Sanity Studio.)_

For each loop over a `node` in `nodes`, I’ll call [a Gatsby function `actions.createPage()`](https://www.gatsbyjs.org/docs/actions/).

1. I’ll check what the `node`’s value for `slug.current` is and tell Gatsby to make the web page it renders available at `https://mysite.com/that-value` by setting `path` in the JavaScript object I pass `createPage()` to `node.slug.current`.
2. I’ll also check what the `node`’s value for `template` is and concatenate it with other data to indicate a file path in my folder structure where Gatsby can find the definition of the React component that I’d like to use for transforming the Markdown-formatted file into HTML on my actual web site. In the case of my one piece of data currently living in Sanity CMS, there’s a property of `template: xyzzy`, and so setting `component` to `path.resolve(`./src/templates/$xyzzy.js`)` will ensure that it is associated with `xyzzy.js`.
3. Finally, I will say that I’d like the `node`’s value for `message` to be passed along to `xyzzy.js` as part of `pageContext` by including it in the `context` property of the JavaScript object I pass `createPage()`. `context` itself takes a JavaScript object as a value, into which I put just one key-value pair: `message` as the key, and `node.message` as the value.

* * *

## Output

Once you deploy these 4 files to a web host capable of building Gatsby sites, such as Netlify or Gatsby Cloud, you’re up and running with your new Gatsby site that pulls its data from Sanity.io.

The resulting page has the following HTML:

```html
<!DOCTYPE html>
<html>
    <head>
        <meta charSet="utf-8"/>
        <meta http-equiv="x-ua-compatible" content="ie=edge"/>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
        <meta name="generator" content="Gatsby 2.23.22"/>
        <link rel="preconnect" href="https://cdn.sanity.io"/>
        <link as="script" rel="preload" href="/webpack-runtime-10d6e7496dd877f2a9f4.js"/>
        <link as="script" rel="preload" href="/framework-a4af6e22a78404f2df50.js"/>
        <link as="script" rel="preload" href="/app-226d7b506f85242e4ac8.js"/>
        <link as="script" rel="preload" href="/component---src-templates-xyzzy-js-96de865fb39f9d696611.js"/>
        <link as="fetch" rel="preload" href="/page-data/index/page-data.json" crossorigin="anonymous"/>
        <link as="fetch" rel="preload" href="/page-data/app-data.json" crossorigin="anonymous"/>
    </head>
    <body>
        <div id="___gatsby">
            <div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper">
                <div>Hello World</div>
            </div>
            <div id="gatsby-announcer" style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0" aria-live="assertive" aria-atomic="true"></div>
        </div>
        <script id="gatsby-script-loader">/*<![CDATA[*/window.pagePath="/";/*]]>*/</script><script id="gatsby-chunk-mapping">/*<![CDATA[*/window.___chunkMapping={"app":["/app-226d7b506f85242e4ac8.js"],"component---src-templates-xyzzy-js":["/component---src-templates-xyzzy-js-96de865fb39f9d696611.js"]};/*]]>*/</script><script src="/component---src-templates-xyzzy-js-96de865fb39f9d696611.js" async=""></script><script src="/app-226d7b506f85242e4ac8.js" async=""></script><script src="/framework-a4af6e22a78404f2df50.js" async=""></script><script src="/webpack-runtime-10d6e7496dd877f2a9f4.js" async=""></script>
    </body>
</html>

```

* * *

## Next steps

The output’s not the fun part, though: stay tuned, because setting up a content editor with as-you-type site previewing is where we’re headed next.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/65-live-editing-animated.gif)

* * *

## Helpful links

* [This codebase on GitHub](https://github.com/kkgthb/web-site-gatsby-05-template-sanity-gatsbyhalf)