Next.js 16 and SanityLive: avoiding request overages
Upgrading to Next.js 16 with SanityLive on next-sanity v12 can multiply prefetch requests and ISR writes, leading to Sanity API overages. What to expect and how next-sanity v13 resolves it.
This issue is resolved in next-sanity v13
The request overage issue described in this article is now resolved. If you're on Next.js 16, upgrade to next-sanity v13. See the next-sanity v13 changelog entry for details.
If you're using SanityLive in a Next.js app on next-sanity v12, upgrading to Next.js 16 can cause a large increase in requests and ISR writes compared to Next.js 15. That increase can drive up Sanity API usage and Vercel ISR costs. next-sanity v13 changes the default cache invalidation behavior to avoid this. This article covers what to expect, what changed in v13, and how to reduce the load if you're still on v12.
This applies if: you're running a Next.js App Router app, using next-sanity's defineLive and <SanityLive>, and you're upgrading from Next.js 15 to 16 on next-sanity v12 (or have already upgraded).
What to expect
On next-sanity v12 with Next.js 16 and <SanityLive>, the default <Link> prefetch behavior combined with how <SanityLive> calls revalidateTag produces a cascade: each prefetch fires more requests than on v15, a live event invalidates the client-side cache, prefetches run again, and routes that match the revalidated tag re-fetch and write to ISR.
In production we've seen an average 4x increase in request load from the same app after upgrading. Worst cases (marketing and docs sites with many segments) are 7–10x or more.
How to tell if this is affecting you
- Your app is on Next.js 16 with
<SanityLive>in use. - Sanity API request counts jumped 4x or more after the upgrade, with no comparable change in traffic.
- Vercel ISR writes spiked on routes that consume Sanity content.
- Browser devtools show multiple
?rscrequests fired for each<Link>prefetch.
Safest way to run SanityLive on Next.js 16 with next-sanity v12
If you can't upgrade to next-sanity v13 yet and you're not using cache components, this is the safest setup on v12:
- Upgrade to at least Next.js 16.2 and enable
experimental.prefetchInlining. - Keep using
sanityFetchfromdefineLivein production, but don't render<SanityLive>unless Presentation Tool or visual editing is active. - Use a sync tag function and set up an
/api/expire-tagshandler in your Next.js app that callsrevalidateTag(tag, "max"). Then call this route from the sync tag function. - When you do render
<SanityLive>(per step 2, for Presentation Tool or visual editing), render it only in draft mode and overriderevalidateSyncTagsso it no longer callsrevalidateTag(tag, { expire: 0 }).
<>
{isDraftMode && <SanityLive revalidateSyncTags={refreshAction} />}
</>The refreshAction implementation must live in a file marked 'use client' (not 'use server') and return 'refresh'. That tells <SanityLive> to call router.refresh() for you, which triggers a single GET that live-updates the page.
'use client'
export async function refreshAction(): Promise<'refresh'> {
return 'refresh'
}Use cache components
next-sanity v13 supports defineLive with Next.js Cache Components (cacheComponents: true). It isn't a drop-in change: Sanity Live with Next.js Cache Components covers the setup steps and the migration path from an existing Sanity Live setup.
Why next-sanity v12 on Next.js 16 causes extra requests
On next-sanity v12, this combination is supported but carries overage risk. The default prefetch behavior on <Link> tags changed in v16 (see Next.js's "Incremental prefetching"). Combined with <SanityLive> calling revalidateTag(tag, { expire: 0 }), the result is:
- Each
<Link>prefetch fires many more requests than in v15. On sanity.io we observed 2 requests with?rscon v15 versus 7 on v16. <SanityLive>receives a live event and callsrevalidateTag(tag, { expire: 0 }). That server action nukes the Next.js client-side cache (router.refresh()has the same effect).- Clearing the client cache empties the prefetch cache. Next.js sees the visible Link tags and prefetches them all again.
- If any of those prefetches hit a route tagged with the revalidated tag, Next.js responds
CACHE: REVALIDATED(its internal signal that a tagged route was re-rendered), which performs a data fetch (counts toward Sanity API usage) and triggers an ISR write (billable on Vercel).
Next.js's core team has confirmed the prefetch request change. The CACHE: REVALIDATED behavior on prefetch links is still under investigation.
Resolution in next-sanity v13
next-sanity v13.0.0 shipped on May 21, 2026. It changes the default cache invalidation behavior on <SanityLive> and adds support for Next.js Cache Components. Upgrading from v12 is a breaking change: the v12 to v13 migration guide lists every change, including the revalidateSyncTags prop, which is replaced by action.