Разработка кастомных схем (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 рабочий день.







