Unlock seamless workflows and faster delivery with our latest releases – get the details

Migrating Custom Structure and Default Document Node

Structure Builder is an API that enables you to reorganize flows and documents inside of Sanity Studio, also known as “the structure.” Common usage might be reorganizing the document type menus or adding custom previews to the document pane. Custom structures were implemented as a part in v2, but can now be passed into the configuration of the structureTool plugin in v3.

Minimal example

Below is how to migrate both a structure definition as well as the getDefaultDocumentNode that lets you define how a document pane should work.

This is how you would do that in v2:

// sanity.json
{
  "root": true,
  "project": {
    "name": "My Project"
  },
  // ...
  "parts": [
    {
      "implements": "part:@sanity/desk-tool/structure",
      "path": "./deskStructure"
    },
  ]
}

// ./deskStructure.js
import S from '@sanity/desk-tool/structure-builder'

export default () =>
  S.list()
    .title('Content')
    .items([
      S.listItem()
        .title('Settings')
        .child(
          S.document()
            .schemaType('siteSettings')
            .documentId('siteSettings')
        ),
      ...S.documentTypeListItems()
    ])

export const getDefaultDocumentNode = ({schemaType}) => {
  // Conditionally return a different configuration based on the schema type
  if (schemaType === "post") {
    return S.document().views([
      S.view.form(),
      S.view.component(WebPreview).title('Web')
    ])  
 }

 return S.document().views([
    S.view.form(),
    S.view.component(JsonView).title('JSON')
   ])
}

And this is the equivalent in v3:

v3

// sanity.config.ts
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {structure, defaultDocumentNode} from './structure'
import { schemaTypes } from './schema'

export default defineConfig({
  name: 'default',
  title: 'My Cool Project',
  projectId: 'my-project-id',
  dataset: 'production',
  plugins: [
    structureTool({
      structure,
      defaultDocumentNode,
    }),
  ],
  schema: schemaTypes
})

// ./structure.js (.ts)
import { WebPreview, JsonView } from './previews'

// note: context includes `currentUser` and the client
export const structure = (S, context) =>
  S.list()
    .title('Content')
    .items([
      S.listItem()
        .title('Settings')
        .child(
          S.document()
            .schemaType('siteSettings')
            .documentId('siteSettings')
        ),
      ...S.documentTypeListItems()
    ])

export const defaultDocumentNode = (S, {schemaType}) => {
  // Conditionally return a different configuration based on the schema type
  if (schemaType === "post") {
    return S.document().views([
      S.view.form(),
      S.view.component(WebPreview).title('Web')
    ])  
 }

 return S.document().views([
    S.view.form(),
    S.view.component(JsonView).title('JSON')
  ])
}

The main difference is that your custom structures are now passed in on the structureTool's structure property. It allows for a function that has the Structure Builder API (aka S) as its first argument and context with the currentUser and the studio client as its second.

This means that if you use import client from "part:@sanity/base/client" in your structure builder definition, then you have to move that to use the client being exposed through the call function.

Similarly, getDefaultDocumentNode from v2 is now the property defaultDocumentNode in the structureTool configuration object. It receives Structure Builder (aka S) as its first argument, and the context with the current schemaType as its second.

Feedback or questions?

These guides are under development. If you have questions or suggestions for improvement, then we want to hear from you. Get in touch via our GitHub discussions page.

Was this article helpful?