Improve anything with user feedback forms and GROQ
When you attach user generated feedback directly to your content, you can query for what needs to be improved
Go to Improve anything with user feedback forms and GROQTurn your Sanity project into a starter that anyone in the community can use with 1 click.
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.
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 functions, 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 new Starter template ready to modify.
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.
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
.
A Starter project follows a specific structure. Our website and studio live in the root of the project in the /studio
and /web
directories. The .sanity-template
directory contains all the metadata about the template, including the proper commands for Netlify to build the project.
Read the full documentation to see more details on structuring your Starter project.
Let’s take a look at the contents of the .sanity-template
directory.
/assets
– A directory for storing assets related to displaying images of 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 exportmanifest.json
– A JSON file containing details about the Starter as well as deployment information.In the manifest.json
file we just created, we need to provide an object of information about our Starter.
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.).
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.
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
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
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.
The /build
directory created by the build
command should be included in your .gitignore
file.
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.
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.
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.
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.
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.
Sanity Composable Content Cloud is the headless CMS that gives you (and your team) a content backend to drive websites and applications with modern tooling. It offers a real-time editing environment for content creators that’s easy to configure but designed to be customized with JavaScript and React when needed. With the hosted document store, you query content freely and easily integrate with any framework or data source to distribute and enrich content.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.
When you attach user generated feedback directly to your content, you can query for what needs to be improved
Go to Improve anything with user feedback forms and GROQContribute to the Sanity Ecosystem
Go to Make your first contribution to the Sanity EcosystemTurn your Sanity and Vercel project into a reusable Starter template
Go to Creating a Sanity and Vercel 1-click Starter ProjectCreate three different custom diff components to visually show changes to data in your documents.
Go to Creating custom diff components for 3 different field types