Налаштування 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 днів. Замовте інтеграцію — ми підготуємо точну оцінку. Отримайте консультацію: наші інженери допоможуть обрати оптимальну архітектуру.







