Налаштування Sanity з Next.js, Nuxt та Remix
Повна інтеграція Sanity з сучасними React-фреймворками
При розробці на Next.js часто виникає проблема гідратації контенту з Sanity, а також необхідність реалізувати preview mode для редакторів. До того ж, без ISR кожна публікація вимагає повної перезбірки — це збільшує TTFB на 30–50%. Ми допоможемо налаштувати інтеграцію Sanity під ключ: з ISR, webhooks та типізацією. Наш досвід — 10+ проєктів, понад 5 років на ринку. Гарантія на роботу — 30 днів після деплою. Зв'яжіться, щоб отримати консультацію та оцінку вашого проєкту.
Sanity працює через HTTP API — будь-який фреймворк може читати контент. Офіційні бібліотеки: next-sanity для Next.js, @sanity/client для інших. Завдяки CDN Sanity Client відповідає в середньому за 50–80 мс, що в 2–3 рази швидше fetch-запитів до звичайного REST API. Офіційна документація Sanity
Переваги Sanity з серверними фреймворками
Sanity — headless CMS з реальним часом: редактори бачать зміни миттєво. У парі з Next.js або Nuxt ви отримуєте статичні сторінки, які оновлюються тільки при зміні контенту. Це знижує навантаження на сервер до 40% і покращує LCP. Крім того, GROQ-запити дозволяють вибирати тільки потрібні поля — обсяг переданих даних скорочується на 60–70%. Інтеграція Sanity з фреймворками зменшує витрати на хостинг.
Як підключити Sanity до Next.js через App Router
Встановіть пакети: npm install next-sanity @sanity/client. Налаштуйте клієнт. Для чернеток використовуйте preview client з токеном.
// lib/sanity/client.ts
import { createClient } from 'next-sanity'
export const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production',
apiVersion: process.env.SANITY_API_VERSION, // встановіть актуальну версію
useCdn: process.env.NODE_ENV === 'production',
})
export const previewClient = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production',
apiVersion: process.env.SANITY_API_VERSION,
useCdn: false,
token: process.env.SANITY_API_TOKEN,
perspective: 'previewDrafts',
})У серверних компонентах використовуйте client.fetch з GROQ-запитами. Приклад сторінки посту:
// app/posts/[slug]/page.tsx
import { client, previewClient } from '@/lib/sanity/client'
import { groq } from 'next-sanity'
import { draftMode } from 'next/headers'
const query = groq`*[_type == "post" && slug.current == $slug][0] {
_id,
title,
body,
publishedAt,
"author": author->{ name },
"slug": slug.current
}`
export default async function PostPage({ params }: { params: { slug: string } }) {
const { isEnabled } = draftMode()
const activeClient = isEnabled ? previewClient : client
const post = await activeClient.fetch(query, { slug: params.slug }, { next: { tags: [`post-${params.slug}`] } })
if (!post) notFound()
return <Article post={post} />
}
export async function generateStaticParams() {
const slugs = await client.fetch<string[]>(`*[_type == "post"].slug.current`)
return slugs.filter(Boolean).map(slug => ({ slug }))
} Як налаштувати ISR через webhook?
ISR оновлює сторінки тільки коли контент змінився — це знижує навантаження на сервер. Створіть webhook в Sanity та ендпоінт, який викликає revalidateTag. Приклад:
// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache'
import { parseBody } from 'next-sanity/webhook'
export async function POST(req: Request) {
try {
const { isValidSignature, body } = await parseBody<{ _type: string; slug?: { current: string } }>(
req,
process.env.SANITY_WEBHOOK_SECRET!
)
if (!isValidSignature) {
return Response.json({ message: 'Invalid signature' }, { status: 401 })
}
if (body._type === 'post') {
revalidateTag('posts')
if (body.slug?.current) {
revalidateTag(`post-${body.slug.current}`)
}
}
return Response.json({ revalidated: true })
} catch (err) {
return Response.json({ message: 'Invalid request' }, { status: 400 })
}
} Інтеграція з Nuxt 3
Встановіть модуль @nuxtjs/sanity та додайте конфігурацію в nuxt.config.ts.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/sanity'],
sanity: {
projectId: process.env.NUXT_PUBLIC_SANITY_PROJECT_ID,
dataset: 'production',
apiVersion: process.env.SANITY_API_VERSION,
useCdn: process.env.NODE_ENV === 'production',
},
})У компоненті використовуйте $sanity для fetch-запитів:
<template>
<article v-if="post">
<h1>{{ post.title }}</h1>
<SanityContent :blocks="post.body" />
</article>
</template>
<script setup lang="ts">
const { $sanity } = useNuxtApp()
const route = useRoute()
const { data: post } = await useAsyncData(`post-${route.params.slug}`, () =>
$sanity.fetch(
`*[_type == "post" && slug.current == $slug][0] { title, body }`,
{ slug: route.params.slug }
)
)
</script> Чи підтримує Remix ISR?
У Remix дані завантажуються в loader-функціях на сервері — сторінка рендериться вже з контентом, без hydration-затримок та клієнтських waterfall-запитів. Використовуйте @sanity/client напряму в loader: client.fetch(query, { slug: params.slug }), потім передайте дані в компонент через useLoaderData.
Remix не підтримує ISR з коробки. Для кешування використовуйте HTTP-заголовки Cache-Control: s-maxage=3600, stale-while-revalidate=86400 в loader — Cloudflare та Vercel Edge підхоплюють їх автоматично. Webhook від Sanity інвалідує кеш через Cloudflare Purge API при публікації нового контенту. Середній час відповіді при правильно налаштованому CDN — 60–100 мс.
Типізація контенту через Sanity TypeGen
Команда npx sanity@latest typegen generate створює TypeScript-типи зі схеми студії. GROQ-запити стають типобезпечними: IDE підказує поля, TypeScript ловить опечатки на етапі збірки. Це економить 1–2 години на кожному новому типі контенту та знижує кількість помилок у production.
Порівняння фреймворків: швидкість роботи з Sanity Client
| Фреймворк | Час першої відповіді (TTFB) | Простота налаштування | Документація |
|---|---|---|---|
| Next.js | Низький (ISR/SSR) | Висока | Відмінна |
| Nuxt 3 | Середній (SSR/SSG) | Висока | Хороша |
| Remix | Низький (loader) | Середня | Хороша |
На практиці Sanity Client швидше fetch-запитів у 2–3 рази завдяки CDN та ефективному кешуванню.
Типові помилки при інтеграції
-
Hydration mismatch через неспівпадіння даних на сервері та клієнті — вирішується синхронізацією запитів через
draftMode. -
CORS errors при запитах з браузера — налаштуйте
CORS originsу панелі Sanity. -
N+1 запити при вкладених посиланнях — використовуйте GROQ-оператор
->для підвантаження пов'язаних документів. - Застарілий кеш при ISR — переконайтеся, що webhook секрет коректний та ендпоінт доступний.
Що входить в роботу
- Налаштування Sanity Client та конфігурація API-версії
- Реалізація preview mode (draft mode) з токенами
- Webhook для on-demand revalidation
- GROQ-запити та типізація контенту (generated types)
- Оптимізація зображень через Sanity Image CDN
- Документація та навчання команди
Як будується процес роботи
- Аналітика: обговорюємо архітектуру контенту та запитів
- Проектування: схеми GROQ-запитів, типи
- Реалізація: інтеграція клієнта, сторінки, preview
- Тестування: перевірка гідратації, помилок ревалідації
- Деплой: налаштування змінних оточення, webhook
Терміни та вартість
| Пакет | Що включено | Термін | Орієнтовна вартість |
|---|---|---|---|
| Базовий | Next.js + ISR + Webhooks | 1–2 дні | від 15 000 грн |
| Розширений | +Nuxt або Remix, preview mode | 2–3 дні | від 30 000 грн |
| Під ключ | Всі фреймворки + TypeGen + документація | 3–5 днів | від 50 000 грн |
Вартість визначається після аналізу вашого проєкту. Орієнтовний час: Next.js App Router — 1–2 дні, Nuxt 3 — 1 день, Remix — 1 день, всі 3 фреймворки — 3–5 днів. Замовте інтеграцію — ми підготуємо точну оцінку. Отримайте консультацію: наші інженери допоможуть обрати оптимальну архітектуру.







