Use Sanity with Next.js

Configuring the Sanity client for Next.js

Reference for Sanity client configuration in Next.js. Covers base config, environment setup, useCdn, feature layers, token handling, and per-request overrides.

The Sanity client is the foundation for all data fetching in a Next.js + Sanity application. This reference covers the base setup and explains what each feature layer adds to it. See the Sanity and Next.js introduction for installation and getting started details.

Base configuration

The minimal client for fetching published content:

This is enough for basic content fetching in Server Components. The following sections explain each option and how to extend this configuration.

Environment variables

Centralize your project configuration in an env.ts file:

The NEXT_PUBLIC_ prefix makes these values available in client-side code. This is safe because project ID and dataset name are not sensitive. They're visible in any API request your frontend makes.

The assertValue helper fails fast with a clear error if an environment variable is missing. This catches misconfiguration at startup instead of producing cryptic errors at runtime.

Set these values in .env.local for local development and in your hosting provider's environment for production. See Sanity and Next.js to get started.

Choose between the API CDN and the live API

Sanity offers a CDN for read queries that caches API responses at the edge. Whether to use it depends on your fetching context:

ScenariouseCdnWhy
Client-side fetches (useEffect, user interactions)trueFast cached responses, reduces API load
High-traffic SSR (for example, personalized feeds)truePrevents API rate limiting under load
Static generation (generateStaticParams)falseNeed guaranteed-fresh data at build time
Webhook-triggered revalidation (ISR or tag-based)falseRevalidated pages must fetch the latest content, not a cached response
Preview or Draft ModefalseMust see unpublished drafts

When in doubt, start with useCdn: true and switch to false for specific use cases using per-request overrides. This matrix applies to requests you make with client.fetch. If you fetch with sanityFetch from defineLive, it sets useCdn for each request from the perspective: the published perspective uses the CDN, and other perspectives, such as drafts, bypass it.

Feature layers

The base configuration works for basic fetching. When you enable additional features, the client configuration grows. Here's what each feature adds and why.

Visual Editing (stega overlays)

To connect click-to-edit overlays in the Presentation Tool to your studio, set the stega.studioUrl option:

The stega.studioUrl option tells the overlays where to open the editor. It doesn't encode anything on its own. During Draft Mode, sanityFetch from defineLive encodes invisible characters into string fields when a serverToken is configured. The overlays use these characters to map rendered text back to its source document and field.

Never allow stega in metadata

See Visual Editing with Next.js App Router for the full setup.

Live Content API

To enable real-time content updates and automatic cache revalidation, configure defineLive with a token:

defineLive takes your base client and returns a sanityFetch function that handles caching and revalidation automatically, plus a <SanityLive /> component that listens for real-time updates.

The token needs Viewer role permissions to fetch draft content. The same token can be used for both serverToken and browserToken. By default, <SanityLive /> sends the browserToken to the browser only when Draft Mode is on. Use a Viewer token, because anyone in Draft Mode can read it.

See the Live Content guide or the Visual Editing guide for the full setup including <SanityLive /> placement and Draft Mode configuration.

Recommended production setup (both features)

For a production application with both Visual Editing and Live Content, use src/sanity/lib/client.ts with the stega option and src/sanity/lib/live.ts with defineLive. Both files appear in full in the "Visual Editing (stega overlays)" and "Live Content API" sections.

Per-request overrides

Use client.withConfig() to create a client variant with different options for specific use cases:

import { client } from '@/sanity/lib/client'

// Bypass CDN for static generation
const freshClient = client.withConfig({ useCdn: false })

// Add a token for authenticated server-side requests
const authClient = client.withConfig({
  token: process.env.SANITY_API_READ_TOKEN,
})

// Disable stega for metadata generation
const metadataClient = client.withConfig({ stega: false })

withConfig() returns a new client instance. The original client is unchanged.

Next steps

Was this page helpful?