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
The type name. Can be an intrinsic type (e.g., 'document', 'object', 'string') or a custom type alias.
The unique name of this schema type. Used to reference the type elsewhere in your schema.
Display title for the type in the studio UI.
Description shown in the studio to help editors understand the type’s purpose.
Array of field definitions for document, object, image, and file types. Use defineField for better type safety.
React component to use as the icon for document types.
Configuration for how documents of this type appear in lists and references.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 rules for the type. The validation API varies by type.
Default value when creating new documents of this type. Can be a value or a function.
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
When false, allows unknown properties in the schema. Use this when adding customizations not part of Sanity core. Default is true.
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:
Name of the fieldset this field belongs to. Fieldsets group related fields together.
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:
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