Skip to main content
Schemas define the structure of your content in Sanity Studio. They’re written in JavaScript or TypeScript and use the defineType and defineField helpers to create type-safe definitions.

Understanding schema types

Sanity has three main categories of schema types:
  • Document types: Top-level content types like posts, authors, or products
  • Object types: Reusable field groups that can be embedded in documents
  • Field types: Individual fields like strings, numbers, images, or arrays

Creating your first schema

1
Import the schema helpers
2
Start by importing defineType and defineField from the sanity package:
3
import {defineType, defineField} from 'sanity'
4
Define a document type
5
Create a basic document type with required metadata:
6
export default defineType({
  name: 'author',
  type: 'document',
  title: 'Author',
  icon: UserIcon,
  description: 'This represents an author',
  fields: [
    // fields go here
  ]
})
7
Add fields to your document
8
Define the fields that make up your document:
9
fields: [
  defineField({
    name: 'name',
    title: 'Name',
    type: 'string',
    description: 'This is the name of the author',
    validation: (rule) => rule.required(),
  }),
  {
    name: 'image',
    title: 'Image',
    type: 'image',
    options: {hotspot: true},
  },
  {
    name: 'role',
    title: 'Role',
    type: 'string',
    options: {
      list: [
        {value: 'developer', title: 'Developer'},
        {value: 'designer', title: 'Designer'},
        {value: 'ops', title: 'Operations'},
      ],
    },
  },
]
10
Configure the preview
11
Define how documents appear in lists and search results:
12
preview: {
  select: {
    title: 'name',
    media: 'image',
    role: 'role',
  },
  prepare({title, media, role}) {
    return {
      title: title,
      media: media,
      subtitle: role ? AUTHOR_ROLES.find(option => option.value === role)?.title : undefined,
    }
  },
}

Field types reference

Sanity provides a rich set of built-in field types:
fields: [
  {name: 'title', type: 'string', title: 'Title'},
  {name: 'count', type: 'number', title: 'Count'},
  {name: 'published', type: 'boolean', title: 'Published'},
  {name: 'publishedAt', type: 'datetime', title: 'Published at'},
  {name: 'content', type: 'text', title: 'Content'},
]

Creating reusable object types

Object types are reusable field groups that can be embedded in multiple documents:
export const myObject = defineType({
  type: 'object',
  name: 'myObject',
  title: 'My object',
  fields: [
    {
      name: 'first',
      type: 'string',
      title: 'First',
    },
    {
      name: 'second',
      type: 'string',
      title: 'Second',
    },
    {
      name: 'image',
      type: 'image',
      title: 'Image',
    },
  ],
})
Then use it in your documents:
fields: [
  {
    name: 'metadata',
    type: 'myObject',
    title: 'Metadata',
  },
]

Arrays and complex structures

Arrays can contain primitives, objects, or references:
fields: [
  // Array of strings
  {
    name: 'tags',
    title: 'Tags',
    type: 'array',
    of: [{type: 'string'}],
  },
  // Array of objects
  {
    name: 'reviews',
    type: 'array',
    of: [
      {
        type: 'object',
        name: 'review',
        fields: [
          {
            name: 'title',
            title: 'Title',
            type: 'string',
            validation: (rule) => rule.required(),
          },
          {
            name: 'rating',
            title: 'Rating',
            type: 'number',
          },
        ],
      },
    ],
  },
]

Validation rules

Add validation to ensure data quality:
defineField({
  name: 'title',
  title: 'Title',
  type: 'string',
  validation: (rule) => rule.required().min(5).max(100),
})
Validation rules are chainable. You can combine multiple rules like .required().min(10).max(200).regex(/^[A-Z]/)

Initial values

Set default values for new documents:
export default defineType({
  name: 'book',
  type: 'document',
  fields: [...],
  initialValue: {
    title: 'Untitled',
    publicationYear: new Date().getFullYear(),
  },
})

Field options and customization

Many field types support options for customization:
{
  name: 'genre',
  title: 'Genre',
  type: 'string',
  options: {
    list: [
      {title: 'Fiction', value: 'fiction'},
      {title: 'Non Fiction', value: 'nonfiction'},
      {title: 'Poetry', value: 'poetry'},
    ],
    layout: 'radio', // or 'dropdown'
    direction: 'horizontal', // or 'vertical'
  },
}
{
  name: 'coverImage',
  title: 'Cover Image',
  type: 'image',
  options: {
    hotspot: true, // Enable image cropping
    metadata: ['blurhash', 'lqip', 'palette'],
  },
}

Organizing fields with fieldsets

Group related fields together:
export default defineType({
  name: 'product',
  type: 'document',
  fieldsets: [
    {
      name: 'pricing',
      title: 'Pricing',
      options: {collapsible: true, collapsed: false},
    },
  ],
  fields: [
    {
      name: 'price',
      type: 'number',
      fieldset: 'pricing',
    },
    {
      name: 'currency',
      type: 'string',
      fieldset: 'pricing',
    },
  ],
})

Adding your schema to the studio

Register your schema types in your studio configuration:
import {defineConfig} from 'sanity'
import author from './schemas/author'
import book from './schemas/book'

export default defineConfig({
  // ... project settings
  schema: {
    types: [author, book],
  },
})
Schema changes are hot-reloaded in development, so you’ll see updates immediately in the studio.

Next steps

Build docs developers (and LLMs) love