Sanity CMS Minimum Viable Build
Tags: webdev, jamstack, tutorial, headlesscms
Published: 2020-07-09 16:07:48

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

Now I’ll set up [Sanity CMS](https://www.sanity.io/) [instead of markdown](https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26) as a data source for the “`Hello World`” in my Gatsby-generated index.html.

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

```

The goal of this tutorial is to make a lovely CMS 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)

And helps me generates output like this that I can plug into Gatsby:

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/46-postman-response.png)

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

```

* * *

## Prerequisites

1. Sign up for a Sanity.io account at [https://accounts.sanity.io/signup/](https://accounts.sanity.io/signup/).    
  - Log into it at [https://manage.sanity.io/](https://manage.sanity.io/).
2. Install the [Node.js](https://nodejs.org) JavaScript execution environment _([here’s a Windows tutorial](https://blog.teamtreehouse.com/install-node-js-npm-windows))_, being sure to include the npm package manager, on your computer.    
  - Make sure that your “path” environment variable for your operating system ends up configured so that when you execute `node -v` and `npm -v` from a command line interface, they both work _(that is, you get a message back saying what version of Node or NPM you’re on)_.
  - This is harder than it sounds if you’re new to installing command-line tools on your computer. Be patient.
3. Install the [Sanity CLI](https://www.sanity.io/docs/getting-started-with-sanity-cli) command-line tool using `npm`.    
  - Make sure that your “path” environment variable for your operating system ends up configured so that when you execute `sanity -v`, you get a message back saying what version of “`@sanity/cli`” you’re on.
  - Did it take days to get this to work? Have a cupcake – you’ve earned it! It’ll be easier from here on out.
4. Optional: Install a tool on your computer capable of helping you make [HTTP requests](https://dev.to/katiekodes/intro-to-http-for-data-folks-managers-especially-24n6), such as [Postman](https://www.postman.com/downloads/), Curl, or a general-purpose programming language with a request-making library _(such as Python)_, and [learn how to use it](https://learning.postman.com/docs/sending-requests/requests/) to make a basic `GET`-typed HTTP request with customized headers.

* * *

## Navigate the command line to an appropriate folder

I decided I wanted to work out of a folder on my hard drive called `C:\example\mysite_sanity`.

Therefore, after I brought up my operating system’s command prompt _(I opened it with **windows-key** , `cmd`, and **enter** on Windows)_, I typed the following at the prompt:

```
cd C:\example\mysite_sanity

```

* * *

## Log the Sanity CLI into Sanity.io

Once there, I type the following into my command line:

```
sanity login

```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/01-sanity-cd-and-login.png)

I tap the **down arrow** on my keyboard until `E-mail / password` is highlighted in turquoise with a `>` to the left of it and hit **enter**.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/02-sanity-login-email.png)

Presuming that my computer’s default web browser is already logged into Sanity.io, I will see a confirmation screen in my web browser that I can close. _(If I’m not logged in in my web browser, I might have to log into my sanity.io account.)_

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/03-sanity-login-success.png)

* * *

## Initialize a new Sanity project

In my command line, I type:

Once there, I type the following into my command line:

```
sanity init

```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/04-sanity-init.png)

I use my keyboard’s **up** and **down** arrow keys to highlight `Create new project` in turquoise _(which also puts a `>` to the left of it)_ and hit **enter**.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/05-sanity-init-settings-arrowdown-arrowup-to-select.png)

I **backspace** out the auto-suggested `(My Sanity Project)` and instead type a name I like for my project.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/06-sanity-init-backspace-this.png)

I personally decided upon **`Gatsby-02`**.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/07-sanity-init-project-name.png)

For demonstration purposes, I overrode the default dataset configuration by typing `n` when asked.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/08-sanity-init-non-default-dataset.png)

Instead, I decided to create a Sanity “dataset” called **`top_secret_stuff`**.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/09-sanity-init-dataset-name.png)

I arrowed up and down until `Private (authenticated requests only)` was highlighted turquoise and had a `>` to the left of it, then hit **enter**.

“Hello World” isn’t really going to be a big secret – it’s going right on my web site – but I want to show you how private data sets get used.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/10-sanity-init-dataset-privacy.png)

Since I had already navigated to `C:\example\mysite_sanity` before starting all this, I don’t have to backspace out and re-type the directory that I’d like to put my local “Sanity project” files in – so I just hit **enter** when Sanity suggests that I install my project there.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/11-sanity-init-enter-for-default-path.png)

We’ll start with as few files as Sanity lets us – I’ll arrow down until I have `Clean project with no predefined schemas` selected and hit **enter**.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/12-sanity-init-clean-project.png)

This is what Sanity looks like while initializing my project. It takes it a moment, because it’s downloading code from the internet.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/13-sanity-init-working.png)

* * *

## Look around the project

Here’s what it looks like in the command line when it’s done:

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/14-sanity-created.png)

And here’s what it looks like at [https://manage.sanity.io](https://manage.sanity.io) when it’s done.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/15-sanity-created-see-sanity-dot-manage-dot-io.png)

If I run this command, I can see it in the context of other projects I created earlier:

```
sanity projects list

```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/16-sanity-projects-list.png)

If I click on my project itself, I’m taken to `https://manage.sanity.io/projects/my-project-id/`.

- Here, my project ID starts with “z” and ends with “m.”
- I don’t yet have a link next to `studio`, which will be my editor – I’ll make one soon enough.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/17-sanity-project-web.png)

Clicking on the “datasets” tab, I can see `top_secret_stuff`.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/18-sanity-project-dataset-web-click-to-change-privacy-or-rename-dataset.png)

Clicking on the “settings” tab, I can change this project’s color theme to purple, just for fun.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/19-sanity-project-settings-color.png)

* * *

## Add an API key to the project

Clicking the “API” navigation item at left, I’ll find a page where I can click `Add New Token`.

Having a token is what will let computer systems read data out of my private dataset.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/20-sanity-add-token.png)

I’ll call mine `Read-Only Token`, set its rights to `Read`, and click `Add New Token`.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/21-token-name.png)

When the token pops up, I have to copy it to my password manager – I can’t get it back.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/22-sanity-token-clipboard.png)

That said, I can easily delete this token and start over if I fail to copy/paste it properly.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/23-sanity-token-confirmed.png)

* * *

## Edit schema files on the hard drive

On my own hard drive at `C:\example\mysite_sanity`, I can see that Sanity installed a bunch of files.

Honestly, I only care about the ones in the **`schemas`** folder.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/24-folder-structure.png)

### `/schemas/schema.js`

`schema.js` in the `schemas` folder is the master file defining my Sanity schema.

I’ll use it to tell Sanity about all the other “schema definition” files I create _(which in this case, there will be just one of)_.

It comes like this:

```
// First, we must import the schema creator
import createSchema from 'part:@sanity/base/schema-creator'

// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:@sanity/base/schema-type'

// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
  // We name our schema
  name: 'default',
  // Then proceed to concatenate our document type
  // to the ones provided by any plugins that are installed
  types: schemaTypes.concat([
    /* Your types here! */
  ])
})

```

I update it to say this:

```
// First, we must import the schema creator
import createSchema from 'part:@sanity/base/schema-creator'

// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:@sanity/base/schema-type'

// We import object and document schemas
import xyzzy from './xyzzy'

// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
  // We name our schema
  name: 'default',
  // Then proceed to concatenate our document type
  // to the ones provided by any plugins that are installed
  types: schemaTypes.concat([
    // The following are document types which will appear
    // in the studio.
    xyzzy
    // When added to this list, object types can be used as
    // { type: 'typename' } in other document schemas
  ])
})

```

### `/schemas/xyzzy.js`

I promised `schema.js` an “`xyzzy`” schema, so I also added a new file to the `schemas` folder and called it `xyzzy.js`.

Its contents are as follows:

```
import icon from 'react-icons/lib/md/note-add'

export default {
  name: 'xyzzy',
  title: 'X y zz y',
  type: 'document',
  icon,
  fields: [
    {
      name: 'template',
      title: 'Template',
      type: 'string'
    },
    {
      name: 'message',
      title: 'Message',
      type: 'string'
    },
    {
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      description: 'If not happy with what the system generated, you can hand-edit it here'
    }
  ],
  preview: {
    select: {
      slug: 'slug',
      template: 'template',
	  message: 'message'
    },
    prepare(selection) {
      const {slug, template, message} = selection
      return {
        title: `${slug.current} [${template}]`,
        subtitle: message
      }
    }
  }
}

```

Since I intend to rebuild this [Gatsby “Hello World” project](https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26) using Sanity’s API instead of Markdown files as a data source, I’m sticking with the notion of each data item that needs to become a “page” having `template` and `message` properties into which I’ll type things like “`xyzzy`” and “`message`.”

_(Maybe it’s a little confusing that I decided to name my Sanity object type `xyzzy` as well as that being the value I intend to type into `template` the first time I use it – sorry.)_

Because there won’t be a folder-of-files structure like `/src/pages/` from which Gatsby can infer what page URL I intend to translate a given piece of data into, I’ll also need to hand-type a URL suffix, or “slug.”

`fields` is where I set all that up.

The `icon` bit at the top just makes things pretty in “Sanity Studio,” as does the `preview` stuff at the bottom.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/25-schema-xyzzy-files.png)

### How to build files like `xyzzy.js`

1. See [Sanity's official schema documentation](https://www.sanity.io/docs/schema-types).
2. Make a 2nd Sanity project on your hard drive where, instead of doing `sanity init` with `Clean project with no predefined schemas`, follow these instructions first with one of the sample options like `Movie project`, `E-commerce`, or `Blog`.  Try to reverse-engineer what "schema" code seems to correspond to what user experiences you see in Sanity Studio.  Personally, I learned a lot from `Movie Project`.

* * *

## Build, deploy, build again, deploy again

To prepare this configuration of Sanity Studio, with my “schema” definitions and all, for deployment to Sanity’s cloud, I run the following command in my command line:

```
sanity build

```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/27-sanity-build-working.png)

Then I run this command:

```
sanity deploy

```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/28-sanity-deploy.png)

The command prompt asks me for a URL prefix at which I’d like to access my “Sanity Studio” for this project.

I chose `gatsby-studio-002`.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/29-sanity-deploy-studio-url.png)

Then, the command line just sort of … does nothing. For 5 minutes. For me, anyway.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/30-sanity-deploy-working.png)

Eventually, refreshing `https://manage.sanity.io/projects/my-project-id/` shows `https://gatsby-studio-002.sanity.studio` as my studio URL, but if I try to visit it, I get a “Studio not found” error as JSON-formatted text.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/31-sanity-studio-while-deploy-working.png)

I gave it a couple more minutes, then hit “ **Ctrl+Break** ” on my keyboard and typed `Y` and hit **enter** to stop this deployment that clearly wasn’t going anywhere.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/32-ctrl-break-deploy-5-minutes.png)

I ran `sanity build` again:

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/34-sanity-build-again-results.png)

Then ran `sanity deploy` again:

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/35-sanity-deploy-again.png)

And this time, in less than a minute, it worked.

That’s been my approach twice now, so hopefully it works for you if you run into trouble.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/36-sanity-deploy-success-less-than-1-min.png)

* * *

## Log into Sanity Studio

Now, visiting `https://gatsby-studio-002.sanity.studio` from my project dashboard, I’m prompted to log in.

I click `E-mail / password`.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/37-sanity-studio-web-login.png)

From there, I arrive at `https://gatsby-studio-002.sanity.studio/desk`, where I see a content type of `X y zz y`, just like I defined as the `title` property in `xyzzy.js`. Neat!

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/38-sanity-studio-desk-home.png)

Clicking on `X y zz y`, I see a plus sign in the far right and click it.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/39-sanity-studio-add-xyzzy.png)

I’m prompted to type in a `template` _(I type `xyzzy`)_, `message` _(I type `Hello World`)_, and `slug` _(I type `/` to indicate that I’d like this content to serve as my web site’s home page)_.

Note that in the top center of the page, I see “`/ [xyzzy]`” in big text and “`Hello World`” in small text as a “preview” of this particular item in my data set, based on the way I’d asked for `title` _(slug followed by the template in square brackets)_ and `subtitle` _(message)_ to be rendered in the `preview` I defined in `xyzzy.js`.

It’s not a particularly _attractive_ preview of my data, but it got the job done for demonstration purposes.

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

* * *

## Test API access

To confirm that my data is really available to the outside world, I fire up [Postman](https://www.postman.com/downloads/).

I set up an [HTTP request](https://dev.to/katiekodes/intro-to-http-for-data-folks-managers-especially-24n6) with a method of `GET`, an endpoint of `https://my-project-id.api.sanity.io/v1/data/export/top_secret_stuff`, an `Authorization` header that starts with the phrase “`Bearer `” and ends with the secret token I saved earlier, and a `Content-Type` header of `application/json`, then hit **Send**.

{% link https://dev.to/katiekodes/intro-to-http-for-data-folks-managers-especially-24n6 %}

At bottom, I can see traces of the data I entered in Sanity’s [HTTP response](https://dev.to/katiekodes/intro-to-http-for-data-folks-managers-especially-24n6) body: part of it mentions `Hello World`, `/`, and `xyzzy` both as the `template` value I typed and, perhaps a bit confusingly – sorry – as the data type of the content itself _(as defined in the `name` property from `xyzzy.js`)_.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/45-postman-view-data.png)

* * *

## Set up GraphQL API access

I also want Sanity to make my data available to the outside world in a way that accepts a data-querying language called [GraphQL](https://graphql.org/learn/), since that's what a prebuilt plugin for Gatsby relies upon when connecting to Sanity to query my data.

If I build an HTTP request in Postman with a method of `POST`, an endpoint of `https://my-project-id.api.sanity.io/v1/graphql/top_secret_stuff/default`, an `Authorization` header that starts with the phrase "`Bearer `" and ends with the secret token I saved earlier, and a Body in **GraphQL** syntax with a blank "**GraphQL Variables**" section but a **Query** section containing the following code:

```graphql
{
  allXyzzy {
    message
    template
    slug {
      current
    }
  }
}
```

Unfortunately, I get the following HTTP response body from Sanity:

```json
{
	"statusCode": 404
	"error": "Not Found",
	"message": "GraphQL schema not found for dataset/tag"
}
```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/47-postman-sanity-graphql-notfound.png)

Bummer.

It turns out that I have to explicitly tell Sanity that I'd like to enable GraphQL-based queries.

I do this by typing the following command into my computer's command prompt:

```
sanity graphql deploy --playground
```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/48-sanity-deploy-graphql.png)

Now when I re-run the same HTTP request that just failed on me, I get the following response body:

```json
{
    "data": {
        "allXyzzy": [
            {
                "message": "Hello World",
                "template": "xyzzy",
                "slug": {
                    "current": "/"
                }
            }
        ]
    }
}
```

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/49a-postman-sanity-graphql-found.png)

Much better!

If you're not used to [writing GraphQL queries](https://graphql.org/learn/) _(I'm certainly not)_, visit `https://your-project-id.api.sanity.io/v1/graphql/your-dataset-name/default`, replacing `your-project-id` and `your-dataset-name`, of course, in a web browser while logged into Sanity.

That's the "playground" you set up by adding the `--playground` flag to your Sanity CLI command deploying a graphql interface for your dataset.

It comes with an editor and a big "run button" where you can make all the typos you want as you learn GraphQL.  It also gives you some hints while you type.

![Screenshot](https://katiekodes.com/images/screenshots/screenshot-gatsby-sanity-2020-07/49b-sanity-graphql-playground.png)

* * *

## Next steps

Stay tuned – next I’ll set up a Gatsby site that not only displays my “Hello World” on the home page, but has a “live preview” that changes as people edit the value of `message` in Sanity Studio.

* * *

![](https://katiekodes.com/images/booksmany.jpg)

## Posts in this series
<!-- With thanks to https://realjenius.com/2012/11/03/jekyll-series-list/ -->

- Part 1 - [Gatsby Minimum Viable Build](https://dev.to/katiekodes/gatsby-minimum-viable-build-3n13)
- Part 2 - [Gatsby React Minimum Viable Markdown Template / Component](https://dev.to/katiekodes/gatsby-react-minimum-viable-markdown-template-component-1e26)
- Part 3 - [Gatsby React WSYIWYG CMS-Friendly Markdown](https://dev.to/katiekodes/gatsby-react-wsyiwyg-cms-friendly-markdown-1npm)
- Part 4 - [Why WYSIWYG static site CMS's love Gatsby](https://dev.to/katiekodes/why-wysiwyg-static-site-cms-s-love-gatsby-jij)
- Part 5 - This Article