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







