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







