Configuration
Sanity Studio lets you quickly get up and running by configuring it with simple JavaScript or TypeScript. Because the configuration is in code, it lets you take advantage of developer tooling and less context switching in making an editing environment.
Typically, you find the studio configuration inside a sanity.config.js
or .ts
file located at the root of your project. The development server for Sanity Studio automatically picks up what's returned from the exported defineConfig
function. This function takes either a single workspace configuration object or an array of configuration objects as its only argument. By implementing the pre-defined properties of this object you are able to customize a range of options and behaviors in the studio, as well as control how plugins and other studio extensions are configured.
Protip
All these are valid file suffixes for the studio configuration file: .js
, .jsx
, .ts
, .tsx
For a single Studio configuration, the defineConfig
function takes a single configuration object. The only required properties are projectId
and dataset
but, since this won’t make for a very useful studio, we've included the structureTool()
-plugin and some schemas in our example to reflect a more typical setup.
More about Schemas and Forms ->
// Single workspace configuration
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {schemaTypes} from './schemas'
export default defineConfig({
projectId: '<projectId>',
dataset: 'production',
plugins: [structureTool()],
schema: {
types: schemaTypes,
},
})
When configuring multiple workspaces you supply an array of configuration objects. Each of these must, in addition to projectId
and dataset
, also include a unique basePath
and name
for each workspace.
// Multiple workspace configuration
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {schemaTypes} from './schemas'
export default defineConfig([
{
projectId: '<projectId>',
dataset: 'production',
name: 'production-workspace',
basePath: '/production',
title: 'Default Workspace',
subtitle: 'production',
plugins: [structureTool()],
schema: {
types: schemaTypes,
},
},
{
projectId: '<projectId>',
dataset: 'staging',
name: 'staging-workspace',
basePath: '/staging',
title: 'Another workspace',
subtitle: 'staging',
plugins: [structureTool()],
schema: {
types: schemaTypes,
},
},
])
Many of the properties of the config object have the option of accepting a callback function instead of a static value. These callbacks are usually invoked with the previous value and a context object.
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {schemaTypes} from './schemas'
export default defineConfig({
projectId: '<projectId>',
dataset: 'production',
plugins: [structureTool()],
schema: {
types: (prev, context) => {
console.log(context);// logs { projectId, dataset }
return [...schemaTypes, ...prev]
},
},
})
Gotcha
If you choose to use the callback function you need to make sure you return the previous value along with whatever new value you want to add. When using static values this is handled automatically by the studio.
The information included in the context object varies depending on the property in question.
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {RocketIcon} from '@sanity/icons'
import {schemaTypes} from './schemas'
export default defineConfig({
projectId: '<projectId>',
dataset: 'production',
plugins: [structureTool()],
schema: {
types: schemaTypes,
},
tools: (prev, context) => {
console.log(context) // logs { getClient, currentUser, schema, projectId, dataset}
return [
{
name: 'my-tool',
title: 'My super-cool tool',
icon: RocketIcon,
component: (props) => <Card>I am a tool, albeit not a useful one</Card>,
},
...prev, // remember to include previous values
]
},
})
Gotcha
The example above includes some JSX in the inline component declaration. Vite, the default studio bundler, requires files that contain JSX to have a file extension or either .jsx
or .tsx
.
Every workspace configuration needs to at least include appropriate string values for dataset
and projectId
. If you are working with multiple workspaces in your studio, each workspace should also include a name
and basePath
.
//⬇ Required
dataset: 'production',
projectId: '<projectId>',
//⬇ Optional if only using a single workspace
name: 'cool-studio',
basePath: '/my-default-workspace',
//⬇ Optional
title: 'My Cool Studio',
subtitle: 'production'
icon: RocketIcon,
The schema
property is where you declare your schema types. You can specify a static array of schema objects or a callback function that returns such an array.
schema: {
types: mySchemas,
}
schema: {
types: (prev, context) => {
console.log(context) // logs { projectId, dataset' }
return [...mySchemas, ...prev]
},
},
You may also set initial value templates using the aptly named templates
property. You can specify a static array of template objects or a callback function that returns such an array.
schema: {
templates: (prev) => [
{
id: 'category-child',
title: 'Category: Child',
schemaType: 'category',
parameters: [{name: `parentId`, title: `Parent ID`, type: `string`}],
value: ({parentId}) => ({
parent: {_type: 'reference', _ref: parentId},
}),
},
{
id: 'article-with-author',
title: 'Article: Author',
schemaType: 'article',
parameters: [{name: `authorId`, title: `Author ID`, type: `string`}],
value: ({authorId}) => ({
author: authorId,
}),
},
...prev,
]
},
This is where you declare plugins for your studio. It accepts a static array of plugin config objects or a callback function that returns such an array. The default studio templates come with the structureTool
plugin included already.
plugins: [structureTool()],
You’ll notice that the plugin function usually needs to be invoked, not just referred to. This is because plugins, by convention, are functions that can accept configuration options as arguments.
plugins: [
structureTool(),
visionTool({
defaultApiVersion: 'v2021-10-21',
defaultDataset: 'production',
}),
],
Tools are full page-components, in that they “take over” most of the studio interface when activated, just like the structure-tool or vision plugin. Because of this behavior they also show up in your studio’s nav bar, and they can be navigated to by appending their name
to your studio’s URL. E.g. https://my-cool-site.com/studio/my-tool
.
Tools are declared much in the same way as plugins. The property accepts either a static array of tool configuration objects or a callback function that returns such an array.
tools: [
{name: 'my-tool', title: 'My Tool', component: MyTool},
{name: 'tool-2', title: '2nd Tool', component: MyOtherTool},
],
// Example using the callback function with some conditional logic
tools: (prev, {currentUser}) => {
if (currentUser.roles.find((r) => r.name === 'admin')) {
return [
...prev,
{name: 'admin', title: 'Admin', component: MyAdminTool},
]
}
return prev
},
The form config property lets you configure asset sources for files and images, as well as override the default rendering of form components.
form: {
file: {
assetSources: myFileAssetSourceResolver,
directUploads: true,
}
image: {
assetSources: myImageAssetSourceResolver,
directUploads: true,
},
components: {
// TODO: Better example
input: (props) => isStringInputProps(props) ? <MyCustomStringInput {...props} /> : props.renderDefault(props),
field: MyCustomField,
}
},
Gotcha
Overriding the rendering of inputs and fields in the top level studio configuration will affect all fields in your studio. If you wish to customize the rendering of only certain fields, you probably want to do so by setting the components property of the appropriate fields. More info: Introduction to Component API.
This property lets you configure document actions and badges, as well as set a productionUrl
for previews and specify options for new documents.
document: {
actions: (prev) =>
prev.map((previousAction) =>
previousAction.action === 'publish' ? MyPublishAction : previousAction
),
productionUrl: (prev, context) => {
return `http://example.com/${context.document?.slug?.current || '404.html'}`
},
},
More about Actions & Badges ->
This property lets you implement custom authentication by providing a configuration object that conforms to the AuthConfig signature.
import {defineConfig} from 'sanity'
/* ... */
auth: {
redirectOnSingle: false,
mode: 'append',
providers: [
{
name: 'vandelay',
title: 'Vandelay Industries',
url: 'https://api.vandelay.industries/login',
logo: '/static/img/vandelay.svg'
}
],
loginMethod: 'dual',
}