Guide

Creating a Sanity and Netlify 1-click Starter Project

Turn your Sanity project into a starter that anyone in the community can use with 1 click.

Bryan Robinson

Bryan is a Developer Relations Specialist at Sanity.

In this guide, we’ll take an existing studio and front end and turn it into a 1-click Starter project. We can re-use this Starter for our own purposes, share it with others, or even submit it to be included as a featured Starter on sanity.io/create.​

Key concepts for Starter creation

Prerequisites

Getting Started

We can create a Starter that includes just a Studio or just a frontend. We can also create a Starter that contains both, or even multiple studios, serverless function, and frontends.

In this guide, we’ll start with a basic clean Studio and a basic frontend that prints JSON data from the Studio. If you want to follow along with the guide, you can get the code by using this starter.

Clone the created repository and you’ll have a directory with a folder named web and a folder named studio. If you want to follow along with your own starter, you can skip this step.

Gotcha

At this point, you’ll want to start this as a new Git repository. You can do this by running rm -rf .git (be careful with the rm command!) in the repository and then initializing a new repository with git init. We do this to have a cleaner history and an easier way to rename our repository to match what the Starter code is expecting.

When you create the new GitHub repository, be sure to name it with the following pattern: sanity-template-usecase-technology.

Structuring your project

A Starter project follows a specific structure. We need to reorganize our code to follow that structure.

Protip

Read the full documentation to see more details on structuring your Starter project.

Currently, our website and our Studio live in directories at the root of our project. We need to move them into a directory called template. The template directory contains all the information that is created when a developer clicks “Create.”

Protip

This directory should usually contain a README file with a description of the starter, project instructions, as well as any pertinent links. You can also initialize an NPM project and install any tools (such as Lerna), which can make running the entire project easier.


Let’s go ahead and create the rest of the directories and files we'll need at the root of our project.

  • /assets – A directory for storing assets related to displaying information about our starter. In this case, preview images for the overall project and for each site the starter contains
  • /data – A directory to store a Sanity dataset export
  • README.md – The README file for this project will be displayed on the Create page.
  • sanity-template.json – A JSON file containing details about the Starter as well as deployment information.

Creating metadata and deployment information in sanity-template.json

In the sanity-template.json file we just created, we need to provide an object of information about our Starter.

Add Starter metadata

To start, we’ll add a bit of information about the starter. We’ll add a title, a description, a preview image, and an array of relevant technologies.

{
  "version": 2,
  "title": "Sanity.io starter template for Netlify",
  "description": "Minimal and barebones example of a starter for deployment on Netlify",
  "previewMedia": {
    "type": "image",
    "src": "assets/netlify.png",
    "alt": "Netlify"
  },
  "technologies": [
    {
      "id": "netlify",
      "name": "Netlify",
      "url": "https://www.netlify.com/"
    }
  ]
}

This information is primarily displayed on sanity.io/create. The version property is important to note. This property is the version of the Create API and should be set to 2.

The overall Starter can have a previewMedia object. This is where we can define out an image to use for the starter. We'll use this same object in the next section when defining our individual sites. This object is not required by the API, but makes for a nicer experience when a developer is looking at the Starter. It also will be important for getting accepted into the featured community Starters list on the Create page.

The technologies array provides a list of relevant technologies. The main technologies of your starter can be listed here (such as Next.js, 11ty, Gatsby, Nuxt.js, etc.).

Add deployment information

Next, we need to provide the Create API with information to pass on to our deployment host. In this case, we'll be using Netlify as our host. We need to provide information about the sites Netlify will be deploying for us, as well as any metadata to show to developers creating the site.

You can publish multiple sites in this way. Each will take a unique id and be configured to either be a studio site or a web site.

{
  // ... Starter metadata omitted for clarity
  "deployment": {
    "provider": "netlify",
    "sites": [
      {
        "id": "studio",
        "type": "studio",
        "title": "Sanity Studio",
        "description": "The Sanity Studio is where you edit and structure your content.",
        "dir": "./studio",
        "previewMedia": {
          "type": "image",
          "src": "assets/studio.jpg",
          "alt": "A preview image of the Sanity Studio."
        },
        "buildSettings": {
          "base": "studio",
          "dir": "dist",
          "cmd": "npm run build && cp netlify.toml dist"
        },
        "requirements": ["build-hook"]
      },
      {
        "id": "web",
        "type": "web",
        "title": "Blog Website",
        "description": "A minimal example of a frontend fetching data from Sanity.io.",
        "dir": "./web",
        "previewMedia": {
          "type": "image",
          "src": "assets/frontend.png",
          "alt": "A preview image of the webpage."
        },
        "buildSettings": {
          "base": "web",
          "dir": "public",
          "cmd": "cp index.html public/index.html"
        },
        "requirements": ["build-hook"],
      }
    ]
  }
  
}

There's a lot to break down in this snippet. Our deployment is represented by an object. The object contains a deployment provider. In this case, it's netlify.

Next, we define each of our sites in a sites array. Each site is represented by an object that contains metadata (similar to our Starter overview), as well as deployment information for our provider.

Each site has a title, description, and preview image like our Starter. This information is displayed on the Starter's landing page. They also require an id and a type. The id is a unique identifying string. The type corresponds to either web for a frontend or studio for a Studio installation. The studio type has a little extra magic to sync things up with a Sanity project.

The dir property contains a string representation of where this site lives relative to the /template directory. This tells the provider where to find the site in Git repository.

The buildSettings object provides details for Netlify to use. The base property is the directory in which Netlify will run its deployment. The dir property is the final "public" directory for Netlify to upload to its CDN. The cmd property is the command for Netlify to run to build the current site.

Once, these values are set, we're ready to test locally.

Testing the Starter locally

In order to test our Starter locally, we need to check that our sanity-template.json doesn't have any errors and run a test build. To do this, we need the sanity-template CLI.

# Install globally
npm install -g sanity-template

Testing JSON data with sanity-template check

Now that we have this installed globally, we can run commands in the CLI from the root of our project.

First, we want to test our configuration in sanity-template.json. Running the following command will show any errors in our JSON data.

# Run from the root of the Starter project
sanity-template check

Running a test build with sanity-template build

Next, we want to see how our template will actually build. To do that, we'll run another command from the CLI in our root directory.

# Run from inside the root directory
sanity-template build

The build command will find the directories and commands we listed in our sanity-template.json file and attempt to find those directories and run those commands. It will then create directories inside of a new /build directory for the final public files.

Gotcha

The /build directory created by the build command should be included in your .gitignore file.

Refactoring out test projectId and dataset

We now have a built frontend and Studio. If we dive into the code for our Studio, we’ll see one small issue: inside /build/studio/sanity.json our project configuration is using our current project information.

{
  "root": true,
  "project": {
    "name": "Netlify POC"
  },
  "api": {
    "projectId": "jmhf2rn8",
    "dataset": "netlify-poc"
  }
}

This is helpful for testing to make sure everything built correctly, but it's not something we want to ship to every developer creating a new site and Studio based on our work. We want each developer’s setup to have their project information.

The project build functionality for a Netlify deploy has the ability to render information from a custom template string in our files. Using <#< variable >#> we can inject data into the build process.

First, we'll take care of our Studio code, by modifying /template/studio/sanity.json.

{
  "root": true,
  "project": {
    "name": "<#< sanity.projectTitle >#>"
  },
  "api": {
    "projectId": "<#< sanity.projectId >#>",
    "dataset": "<#< sanity.dataset >#>"
  },
  
  // ... rest of the file omitted for clarity
}

Next, we need to modify anywhere our Sanity API information is stored in our frontend. In this basic example, we need to modify /template/site/utils/SanityClient.js.

const sanityClient = require('@sanity/client');
const client = sanityClient({
  projectId: "<#< sanity.projectId >#>",
  dataset: "<#< sanity.dataset >#>",
  useCdn: true 
})

module.exports = client;

This code will work when a developer clicks "Create," however, when we run it locally with sanity-template build we get empty strings for each variable. To get this to work, we need to provide a JSON file with the data to the build command.

In the root folder, we'll create a file named template-values-development.json (this can be named anything). In this file, we'll provide the variables the template strings are expecting. These should relate to the dataset for your project.

{
  "sanity": {
    "dataset": "your-dataset",
    "projectId": "your-project-id",
    "projectTitle": "Netlify POC"
  }
}

After we have the file, we need to tell the build command to use the values in that file.

sanity-template build --template-values template-values-development.json

Now, when you look in the build directory, the values should all be present.

Protip

This flag in the CLI also works in the sanity-template watch command. As you actively develop your template, this can be helpful to watch and rebuild all the sites listed.

Seeding our Starter with data

Whether we’re creating a Starter for our future selves or creating it for the community at large, seeding our Starter with a little data can go a long way.

To seed the project, we'll want to create data inside our test project. The project doesn’t have any Schema defined yet, so we can’t add data. Let's fix that and add a very basic blog schema.

import createSchema from 'part:@sanity/base/schema-creator'
import schemaTypes from 'all:part:@sanity/base/schema-type'

export default createSchema({
  name: 'default',
  types: schemaTypes.concat([
    {
      name: 'blog',
      title: 'Blog Posts',
      type: 'document',
        fields: [
          {
            name: 'name',
            title: 'Title',
            type: 'string'
          },
          {
            title: 'Slug',
            name: 'slug',
            type: 'slug',
            options: {
              source: 'name'
            },
          },
          {
            title: 'Body',
            name: 'body',
            type: 'array',
            of: [{type: 'block'}]
          },    
      ]
    }
  ])
})

After the schema is created, we’ll start our Studio and add an example blog post.

Once the sample content has been added to our dataset, we can export it out using the sanity dataset export command in the root of the Studio we’re working in. When asked where you want to export the data, you’ll want to tell the CLI to put it in the root of our project in the /data folder we created. This will create a compressed file that the Create site will decompress and import into the new project set up by the script.

Set up automatic updating with Renovatebot

Keeping your starter up to date is important. It can also be a pain. We can use Renovate​ to keep an eye on certain packages and issue pull requests when they get out of date.

For the purposes of this guide, we’ll take a look at how we can set up Renovate to watch out for updates to Sanity and its various plugins. Renovate is a third-party watcher that can be configured as a GitHub app. For details on setting it up on your GitHub account, you can check out their docs.

Once Renovate is set up to watch our repository, we need to give it some instructions. To configure what Renovate is watching, we'll add a renovate.json to the root of our Starter.

In the JSON file, we define out any custom configuration. In our case, we want to watch anything associated with Sanity, which luckily, the Sanity team has set up as a preset we can use.

{
  "extends": [
    "github>sanity-io/renovate-presets:sanity-template"
  ]
}

This extends Sanity's presets which include anything prefixed with @sanity or sanity-plugin. See the configuration on GitHub to read the full file.

Share your Starter

At this point, your starter is ready to be used by anyone with the right link. Your repository's link will follow this pattern:

https://sanity.io/create?template=<github-username>/repository-name. Test it live and then share it out.

If you want to be included in the Community section of the Create page, be sure to let us know in the #i-made-this channel in our Slack community.