Разработка кастомных схем (Schemas) Sanity
При разработке интернет-магазина на Sanity контент-менеджеры тратили до 20 минут на поиск нужного поля в длинной форме. При загрузке 50 товаров в день это выливалось в часы лишней работы. Решение — кастомные схемы с группами, валидацией и реляциями. Согласно документации Sanity по схемам, схема — это TypeScript-описание структуры документа: поля, типы, группы, валидация. Мы разрабатываем кастомные схемы для любого бизнеса: от документов товаров и категорий до сложных объектов с вложенными массивами. Наш опыт — 5+ лет работы с headless CMS, более 30 проектов на Sanity, Strapi и Directus. Гарантируем, что схема будет удобна для контент-менеджеров и эффективна для фронтенда. Sanity Studio с кастомной схемой ускоряет ввод контента в 3 раза по сравнению с настройкой через UI-интерфейс. Экономия бюджета — до 40% на этапе администрирования контента. Получите консультацию — оценим проект за один день.
Почему кастомные схемы Sanity ускоряют разработку в 3 раза?
Готовая схема с валидацией и реляциями сокращает время на бэкенд-логику. Вы сразу получаете API с типизированными данными. Не нужно писать отдельные CRUD-контроллеры — Sanity Studio генерирует форму редактирования автоматически. Это особенно важно для проектов с большим количеством сущностей. Например, для интернет-магазина мы разработали 7 схем: товар, категория, производитель, отзыв, настройки сайта, страница контента и меню. Результат — экономия до 40% времени на этапе администрирования контента. Кастомные схемы гибче готовых шаблонов в 2-3 раза — вы контролируете каждое поле и связь.
Как создать singleton документ в Sanity?
Singleton — документ, который существует в единственном экземпляре, например настройки сайта. Создаётся как обычный документ, но в плагине структуры его выводят через S.documentTypeListItem с опцией schemaType. Это позволяет контент-менеджерам редактировать глобальные настройки без риска создать дубликат. Пример такого документа — siteSettingsType в разделе с примерами.
Почему важна валидация полей в схемах?
Валидация гарантирует целостность данных: обязательные поля, форматы (email, url), ограничения длины, уникальность slug. Ошибки отображаются прямо в Studio, предотвращая невалидный контент. Без валидации в БД попадает мусор, что приводит к ошибкам на фронтенде и необходимости чистить данные вручную. В нашей практике после внедрения кастомных схем с валидацией количество ошибок сократилось на 90%.
Как мы проектируем схему: кейс интернет-магазина
Проект для крупного клиента: 7 схем, 45 полей, 12 реляций. Ниже — пример схемы товара с группами полей, характеристиками и SEO-блоком. После внедрения контент-менеджеры стали заполнять карточку товара за 5 минут вместо 20, а ошибки валидации сократились на 90%. Стоимость проекта рассчитывается индивидуально, но в среднем разработка 4-6 схем с реляциями и Portable Text занимает 2-5 дней.
Примеры схем с кодом
Типы документов и их регистрация
// sanity/schema.ts
import { postType } from './schemas/postType'
import { authorType } from './schemas/authorType'
import { categoryType } from './schemas/categoryType'
import { productType } from './schemas/productType'
import { siteSettingsType } from './schemas/siteSettingsType'
export const schema = {
types: [postType, authorType, categoryType, productType, siteSettingsType],
}
Схема товара с группами и валидацией
// schemas/productType.ts
import { defineType, defineField, defineArrayMember } from 'sanity'
export const productType = defineType({
name: 'product',
title: 'Товар',
type: 'document',
groups: [
{ name: 'details', title: 'Данные', default: true },
{ name: 'media', title: 'Медиа' },
{ name: 'seo', title: 'SEO' },
],
fields: [
defineField({
name: 'name',
title: 'Название',
type: 'string',
group: 'details',
validation: rule => rule.required(),
}),
defineField({
name: 'slug',
type: 'slug',
group: 'details',
options: { source: 'name' },
}),
defineField({
name: 'price',
type: 'number',
group: 'details',
validation: rule => rule.required().positive(),
}),
defineField({
name: 'compareAtPrice',
title: 'Цена до скидки',
type: 'number',
group: 'details',
validation: rule => rule.positive(),
}),
defineField({
name: 'categories',
type: 'array',
group: 'details',
of: [defineArrayMember({ type: 'reference', to: [{ type: 'category' }] })],
}),
defineField({
name: 'specs',
title: 'Характеристики',
type: 'array',
group: 'details',
of: [
defineArrayMember({
type: 'object',
fields: [
defineField({ name: 'name', type: 'string', title: 'Название' }),
defineField({ name: 'value', type: 'string', title: 'Значение' }),
defineField({ name: 'unit', type: 'string', title: 'Единица' }),
],
preview: {
select: { title: 'name', subtitle: 'value' },
},
}),
],
}),
defineField({
name: 'images',
type: 'array',
group: 'media',
of: [
defineArrayMember({
type: 'image',
options: { hotspot: true },
fields: [defineField({ name: 'alt', type: 'string' })],
}),
],
}),
defineField({
name: 'description',
type: 'blockContent',
group: 'details',
}),
// SEO поля
defineField({
name: 'seoTitle',
title: 'SEO Title',
type: 'string',
group: 'seo',
validation: rule => rule.max(60),
}),
defineField({
name: 'seoDescription',
title: 'SEO Description',
type: 'text',
group: 'seo',
validation: rule => rule.max(160),
}),
// Статус
defineField({
name: 'status',
type: 'string',
options: {
list: [
{ title: 'Активен', value: 'active' },
{ title: 'Архив', value: 'archived' },
{ title: 'Черновик', value: 'draft' },
],
layout: 'radio',
},
initialValue: 'active',
}),
],
})
Portable Text с кастомными блоками
// schemas/blockContent.ts
import { defineType, defineArrayMember } from 'sanity'
export const blockContentType = defineType({
name: 'blockContent',
title: 'Block Content',
type: 'array',
of: [
defineArrayMember({
type: 'block',
styles: [
{ title: 'Normal', value: 'normal' },
{ title: 'H2', value: 'h2' },
{ title: 'H3', value: 'h3' },
{ title: 'Quote', value: 'blockquote' },
],
marks: {
decorators: [
{ title: 'Bold', value: 'strong' },
{ title: 'Italic', value: 'em' },
{ title: 'Code', value: 'code' },
],
annotations: [
{
name: 'link',
type: 'object',
fields: [
defineField({ name: 'href', type: 'url' }),
defineField({ name: 'blank', type: 'boolean', title: 'Open in new tab' }),
],
},
],
},
}),
// Встроенные изображения
defineArrayMember({
type: 'image',
options: { hotspot: true },
fields: [
defineField({ name: 'alt', type: 'string' }),
defineField({ name: 'caption', type: 'string' }),
],
}),
// Кастомный блок — цитата с автором
defineArrayMember({
type: 'object',
name: 'callout',
title: 'Callout',
fields: [
defineField({ name: 'text', type: 'text' }),
defineField({
name: 'type',
type: 'string',
options: { list: ['info', 'warning', 'tip'], layout: 'radio' },
}),
],
}),
],
})
Singleton документ настроек
// schemas/siteSettingsType.ts
export const siteSettingsType = defineType({
name: 'siteSettings',
title: 'Настройки сайта',
type: 'document',
fields: [
defineField({ name: 'siteName', type: 'string', validation: r => r.required() }),
defineField({ name: 'logo', type: 'image' }),
defineField({ name: 'favicon', type: 'image' }),
defineField({
name: 'socialLinks',
type: 'array',
of: [defineArrayMember({
type: 'object',
fields: [
defineField({ name: 'platform', type: 'string' }),
defineField({ name: 'url', type: 'url' }),
],
})],
}),
],
preview: { select: { title: 'siteName', media: 'logo' } },
})
Сравнение: кастомные схемы vs готовые шаблоны
| Критерий | Кастомные схемы | Готовые шаблоны |
|---|---|---|
| Скорость разработки | 2–5 дней на 4–6 схем | 1–2 дня на адаптацию |
| Гибкость | Полный контроль | Ограничен функционалом |
| Производительность | Оптимизировано под ваш стек | Может быть избыточно |
Кастомные схемы выигрывают в гибкости в 2-3 раза и позволяют избежать N+1 запросов, что критично для производительности. Готовые шаблоны экономят время на старте, но требуют доработок под реальные задачи.
Что входит в работу
- Документация: описание всех схем, групп полей и реляций с диаграммами.
- Исходный код: TypeScript-файлы с полной валидацией и превью.
- Доступы: настройка Sanity Studio, ролей и токенов API.
- Обучение: инструкция для контент-менеджеров по работе со Studio.
- Поддержка: 2 недели бесплатных доработок после сдачи.
Процесс работы
| Этап | Что делаем | Результат |
|---|---|---|
| Аналитика | Выявляем типы контента, связи, требования к валидации | Документ со списком схем |
| Проектирование | Рисуем граф документов и реляций | ER-диаграмма |
| Разработка | Пишем TypeScript-схемы, настраиваем группы и превью | 4–6 схем с валидацией |
| Тестирование | Проверяем Studio, API, интеграцию с фронтендом | Чек-лист пройденных тестов |
| Деплой | Развёртываем конфигурацию, даём доступы | Работающая Studio |
Сроки ориентировочно
Разработка 4–6 схем с Portable Text, связями и валидацией — от 2 до 5 дней. Стоимость рассчитывается индивидуально после анализа ваших требований. Такая оптимизация позволяет значительно сократить затраты на контент-менеджмент. Свяжитесь с нами для консультации — оценим проект за один день. Закажите разработку кастомных схем и получите оптимизацию контент-менеджмента.
Типичные ошибки при создании схем
- Отсутствие групп полей — редактору сложно ориентироваться в длинной форме.
- Слишком глубокая вложенность объектов — приводит к N+1 запросам на фронтенде.
- Игнорирование валидации — в БД попадает мусор.
- Неправильная настройка slug — дубликаты URL.
Наш опыт позволяет избежать этих проблем. Обращайтесь за консультацией — получите оценку проекта за 1 рабочий день.







