Loading...
Loading...
Integrates Sanity Live with Next.js Cache Components in next-sanity v13+ apps. Sets up sanityFetch, <SanityLive>, Visual Editing, Presentation Tool, draft mode handling, and the three-layer (Page/Dynamic/Cached) component pattern with explicit perspective/stega prop-drilling. Use when configuring or migrating a Next.js app to cacheComponents with Sanity, when adding sanityFetch, when wiring <SanityLive>/<VisualEditing>, or when refactoring components that hardcode perspective/stega.
npx skill4agent add sanity-io/next-sanity sanity-live-cache-componentsnext-sanitycacheComponents: truesanityFetchcacheTagcacheLife<SanityLive>node_modules/next/dist/docs/next-cache-components'use cache'cacheLifecacheTagawait draftMode()'use cache'use cachepackage.jsonpnpm list nextnpm ls nextpnpm view next versionAGENTS.mdNEXT_PUBLIC_SANITY_PROJECT_IDNEXT_PUBLIC_SANITY_DATASETSANITY_API_READ_TOKENsanity.config.tssanity.cli.tssanity/| File | When to read |
|---|---|
| reference/live-helpers.md | Full |
| reference/three-layer-pattern.md | The Page → Dynamic → Cached pattern for |
| reference/layouts.md | Non-blocking data fetching inside |
| reference/dynamic-segments.md | High-performance |
next-sanity@^13npm install next-sanity@^13 --save-exactdefineLiveclient.tslive.tstokenstega.*perspective: 'published'stega: falsesanityFetchperspectivestegagetDynamicFetchOptionssanityFetchgenerateStaticParamssanityFetchStaticParamssanityFetchgenerateMetadatasitemap.tsopengraph-image.tsxsanityFetchMetadatasanityFetch'use server''use cache'<SanityLive><VisualEditing>next.config.tscacheComponentscacheLife.defaultsanitysanityFetch// next.config.ts
import type {NextConfig} from 'next'
import {sanity} from 'next-sanity/live/cache-life'
const nextConfig: NextConfig = {
cacheComponents: true,
cacheLife: {default: sanity},
}
export default nextConfigdefineLivesrc/sanity/lib/client.tssrc/sanity/lib/live.tsdefineLive// src/sanity/lib/live.ts (excerpt)
export const {SanityLive, sanityFetch} = defineLive({
client,
serverToken: token,
browserToken: token,
strict: true,
})client.tsgetDynamicFetchOptionssanityFetchMetadatasanityFetchStaticParamslive.ts| Helper | Used in |
|---|---|
| |
| |
| |
| Resolving |
| Rendered once in a root layout |
<SanityLive><SanityLive><VisualEditing>layout.tsxpage.tsxincludeDraftsdefineLivestrict: trueincludeDrafts={isDraftMode}<SanityLive>onErroronWelcomeonReconnect// src/app/layout.tsx
import {SanityLive} from '@/sanity/lib/live'
import {VisualEditing} from 'next-sanity/visual-editing'
import {draftMode} from 'next/headers'
export default async function RootLayout({children}: LayoutProps<'/'>) {
const {isEnabled: isDraftMode} = await draftMode()
return (
<html lang="en">
<body>
{children}
<SanityLive includeDrafts={isDraftMode} />
{isDraftMode && <VisualEditing />}
</body>
</html>
)
}NextStudionext-sanity/studioapp/studio/[[...index]]/page.tsx<SanityLive><SanityLive>src/app/(website)/layout.tsxsrc/app/(website)Page/Layout (Layer 1: draftMode branch)
├── NOT draft mode → <CachedX perspective="published" stega={false} /> (no Suspense)
└── draft mode → <Suspense fallback={...}>
<DynamicX params={params} /> (Layer 2: awaits dynamic APIs)
└── <CachedX perspective={p} stega={s} /> (Layer 3: 'use cache')'use cache'PageLayout'use cache'paramssearchParamscookies()getDynamicFetchOptions'use cache''use cache''use cache'page.tsxgenerateStaticParamspage.tsxsearchParamssearchParamslayout.tsx[slug]loading.tsxgenerateStaticParamsparamsperspective: 'published'stega: falsesanityFetchperspectivestegagetDynamicFetchOptionssanityFetch('use server''use cache'sanityFetch(generateStaticParamssanityFetchStaticParamssanityFetch(generateMetadatagenerateViewportsitemap.tsrobots.tsopengraph-image.tsxsanityFetchMetadataperspectivegetDynamicFetchOptionsawait draftMode()await getDynamicFetchOptions()page.tsxlayout.tsxloading.tsx<Suspense><SanityLive><VisualEditing>