Skip to main content

defineType, defineField, defineArrayMember

Helper functions for defining schema types, fields, and array members in Sanity Studio. These functions provide type safety and autocompletion in your IDE while building schemas.

defineType

Defines a schema type definition. Schema types defined with defineType are typically added to the Studio config under schema.types.

Function Signature

function defineType<
  const TType extends IntrinsicTypeName | string,
  const TName extends string,
  TSelect extends Record<string, string> | undefined,
  TPrepareValue extends Record<keyof TSelect, any> | undefined,
  TAlias extends IntrinsicTypeName | undefined,
  TStrict extends boolean | undefined,
>(
  schemaDefinition: SchemaDefinition,
  defineOptions?: DefineSchemaOptions<TStrict, TAlias>
): SchemaDefinition

Parameters

type
string
required
The type name. Can be an intrinsic type (e.g., 'document', 'object', 'string') or a custom type alias.
name
string
required
The unique name of this schema type. Used to reference the type elsewhere in your schema.
title
string
Display title for the type in the studio UI.
description
string
Description shown in the studio to help editors understand the type’s purpose.
fields
FieldDefinition[]
Array of field definitions for document, object, image, and file types. Use defineField for better type safety.
icon
ComponentType
React component to use as the icon for document types.
preview
PreviewConfig
Configuration for how documents of this type appear in lists and references.
preview.select
Record<string, string>
Fields to select for the preview. Keys are variable names, values are field paths.
preview.prepare
(selection: SelectionResult) => {title?: string, subtitle?: string, media?: ReactNode}
Function to prepare the preview data for display.
validation
ValidationBuilder
Validation rules for the type. The validation API varies by type.
initialValue
InitialValueProperty
Default value when creating new documents of this type. Can be a value or a function.
options
object
Type-specific options. Varies by intrinsic type (e.g., ArrayOptions, StringOptions).
hidden
boolean | ConditionalProperty
Whether the type should be hidden in the studio. Can be a boolean or a function that receives context.
readOnly
boolean | ConditionalProperty
Whether the type is read-only. Can be a boolean or a function.

Define Options

strict
boolean
When false, allows unknown properties in the schema. Use this when adding customizations not part of Sanity core. Default is true.
aliasFor
IntrinsicTypeName
Provide the base type name when defining a type alias. Improves type safety by enforcing that the definition conforms to the base type.

defineField

Defines a field within a document, object, image, or file definition’s fields array. Provides improved autocompletion and type-specific validation.

Function Signature

function defineField<
  const TType extends IntrinsicTypeName | string,
  const TName extends string,
  // ... other type parameters
>(
  schemaField: FieldDefinition,
  defineOptions?: DefineSchemaOptions<TStrict, TAlias>
): FieldDefinition

Parameters

Same as defineType, with additional field-specific properties:
fieldset
string
Name of the fieldset this field belongs to. Fieldsets group related fields together.
group
string | string[]
Name(s) of the group(s) this field belongs to. Groups organize fields into tabs.

defineArrayMember

Defines an array item member type within an array definition’s of array. Provides improved autocompletion for array member types.

Function Signature

function defineArrayMember<
  const TType extends IntrinsicTypeName | string,
  const TName extends string,
  // ... other type parameters
>(
  arrayOfSchema: ArrayMemberDefinition,
  defineOptions?: DefineSchemaOptions<TStrict, TAlias>
): ArrayMemberDefinition

Parameters

Similar to defineType, but:
name
string
Optional for array members. When provided, name is used as _type for the array item when stored. Necessary when an array contains multiple entries with the same type, each with different configuration.

Examples

Document Type

import {defineType, defineField} from 'sanity'
import {BookIcon} from '@sanity/icons'

export default defineType({
  name: 'book',
  type: 'document',
  title: 'Book',
  icon: BookIcon,
  fields: [
    defineField({
      name: 'title',
      type: 'string',
      title: 'Title',
      validation: (rule) => rule.required().min(5).max(100),
    }),
    defineField({
      name: 'author',
      type: 'reference',
      title: 'Author',
      to: [{type: 'author'}],
    }),
    defineField({
      name: 'publicationYear',
      type: 'number',
      title: 'Year of Publication',
    }),
  ],
  preview: {
    select: {
      title: 'title',
      author: 'author.name',
      media: 'coverImage',
    },
    prepare({title, author, media}) {
      return {
        title,
        subtitle: author ? `By ${author}` : 'No author',
        media,
      }
    },
  },
})

Object Type

import {defineType, defineField} from 'sanity'

export const address = defineType({
  name: 'address',
  type: 'object',
  title: 'Address',
  fields: [
    defineField({
      name: 'street',
      type: 'string',
      title: 'Street Address',
    }),
    defineField({
      name: 'city',
      type: 'string',
      title: 'City',
    }),
    defineField({
      name: 'postalCode',
      type: 'string',
      title: 'Postal Code',
    }),
    defineField({
      name: 'country',
      type: 'string',
      title: 'Country',
    }),
  ],
})

Array Field with Members

import {defineField, defineArrayMember} from 'sanity'

defineField({
  name: 'tags',
  type: 'array',
  title: 'Tags',
  of: [
    defineArrayMember({
      type: 'string',
    }),
  ],
})

Complex Array with Multiple Types

import {defineField, defineArrayMember} from 'sanity'

defineField({
  name: 'content',
  type: 'array',
  title: 'Content',
  of: [
    defineArrayMember({
      type: 'block',
      styles: [
        {title: 'Normal', value: 'normal'},
        {title: 'H1', value: 'h1'},
        {title: 'H2', value: 'h2'},
      ],
      marks: {
        decorators: [
          {title: 'Strong', value: 'strong'},
          {title: 'Emphasis', value: 'em'},
        ],
      },
    }),
    defineArrayMember({
      type: 'image',
      name: 'inlineImage',
      options: {hotspot: true},
      fields: [
        defineField({
          name: 'caption',
          type: 'string',
          title: 'Caption',
        }),
        defineField({
          name: 'alt',
          type: 'string',
          title: 'Alt Text',
          validation: (rule) => rule.required(),
        }),
      ],
    }),
  ],
})

Custom Type with Image Fields

import {defineType, defineField} from 'sanity'

export const author = defineType({
  name: 'author',
  type: 'document',
  title: 'Author',
  fields: [
    defineField({
      name: 'name',
      type: 'string',
      title: 'Name',
      validation: (rule) => rule.required(),
    }),
    defineField({
      name: 'image',
      type: 'image',
      title: 'Profile Picture',
      options: {
        hotspot: true,
      },
      fields: [
        defineField({
          name: 'alt',
          type: 'string',
          title: 'Alt Text',
        }),
      ],
    }),
    defineField({
      name: 'bio',
      type: 'array',
      title: 'Biography',
      of: [{type: 'block'}],
    }),
  ],
})

Type Alias with aliasFor

import {defineType} from 'sanity'

// First, define a custom object type
export const customObject = defineType({
  name: 'customObject',
  type: 'object',
  fields: [
    {name: 'title', type: 'string'},
  ],
})

// Then, create an alias that extends it
export const extendedCustomObject = defineType(
  {
    name: 'extendedCustomObject',
    type: 'customObject', // References the custom type
    // TypeScript knows this should conform to object type
    options: {
      collapsible: true,
    },
  },
  {aliasFor: 'object'} // Tells TypeScript the base type
)

Conditional Fields

import {defineType, defineField} from 'sanity'

export const product = defineType({
  name: 'product',
  type: 'document',
  title: 'Product',
  fields: [
    defineField({
      name: 'title',
      type: 'string',
      title: 'Title',
    }),
    defineField({
      name: 'hasVariants',
      type: 'boolean',
      title: 'Has Variants',
    }),
    defineField({
      name: 'variants',
      type: 'array',
      title: 'Variants',
      // Hide this field when hasVariants is false
      hidden: ({parent}) => !parent?.hasVariants,
      of: [
        {
          type: 'object',
          fields: [
            {name: 'name', type: 'string'},
            {name: 'sku', type: 'string'},
          ],
        },
      ],
    }),
  ],
})

Type Safety

These functions don’t modify the schema at runtime—they’re identity functions that return the input unchanged. Their purpose is to provide TypeScript type narrowing and IDE autocompletion.

Maximum Type Safety

For best autocompletion and type checking, use all three functions together:
import {defineType, defineField, defineArrayMember} from 'sanity'

defineType({
  type: 'object',
  name: 'custom-object',
  fields: [
    defineField({
      type: 'array',
      name: 'arrayField',
      title: 'Things',
      of: [
        defineArrayMember({
          type: 'object',
          name: 'item',
          fields: [
            defineField({
              type: 'string',
              name: 'title',
              title: 'Title',
            }),
          ],
        }),
      ],
    }),
  ],
})
Without these wrappers, TypeScript resolves to a union type of all possible properties across all schema types, resulting in less precise typing.

Extending Schema Types

You can extend Sanity schema types with custom properties using TypeScript declaration merging:
// types.ts
declare module '@sanity/types' {
  export interface StringOptions {
    myCustomOption?: boolean
  }
}

// schema.ts
import {defineType} from 'sanity'

defineType({
  type: 'string',
  name: 'my-string',
  options: {
    myCustomOption: true, // Now type-safe!
  },
})

Source Location

packages/@sanity/types/src/schema/define.ts

Build docs developers (and LLMs) love