next-sanity v11.0.0: Moves VisualEditing, defineLive, and isCorsOriginError exports to subpaths

This major version update introduces changes to how applications must import VisualEditing, defineLive, and isCorsOriginError.

Breaking changes

This release moves the VisualEditing, defineLive, and isCorsOriginError exports to subpaths. This is necessary to allow support for output: static builds.

These changes are required for all projects updating to next-sanity v11 or later, regardless if they use static output builds.

Update steps

Update to the latest version of next-sanity:

npm install next-sanity@latest

pnpm add next-sanity@latest

After installing next-sanity v11 or higher, update any imports for VisualEditing, defineLive, and isCorsOriginError to use the associated paths instead of the root as shown in the examples below.

VisualEditing

import {VisualEditing} from 'next-sanity/visual-editing'
import {SanityLive} from '@/sanity/lib/live'

export default function RootLayout({children}: {children: React.ReactNode}) {
return (


{children}
<SanityLive />
{(await draftMode()).isEnabled && <VisualEditing />}


)
}

import {VisualEditing} from 'next-sanity'
import {SanityLive} from '@/sanity/lib/live'

export default function RootLayout({children}: {children: React.ReactNode}) {
return (


{children}
<SanityLive />
{(await draftMode()).isEnabled && <VisualEditing />}


)
}

defineLive

Import defineLive from the next-sanity/live path.

import {createClient} from 'next-sanity'
import {defineLive} from 'next-sanity/live'

const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
useCdn: true,
apiVersion: 'v2025-03-04',
stega: {studioUrl: '/studio'},
})

const token = process.env.SANITY_API_READ_TOKEN
if (!token) {
throw new Error('Missing SANITY_API_READ_TOKEN')
}

export const {sanityFetch, SanityLive} = defineLive({
client,
serverToken: token,
browserToken: token,
})

import {createClient} from 'next-sanity'
import {defineLive} from 'next-sanity'

const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
useCdn: true,
apiVersion: 'v2025-03-04',
stega: {studioUrl: '/studio'},
})

const token = process.env.SANITY_API_READ_TOKEN
if (!token) {
throw new Error('Missing SANITY_API_READ_TOKEN')
}

export const {sanityFetch, SanityLive} = defineLive({
client,
serverToken: token,
browserToken: token,
})

isCorsOriginError

Import isCorsOriginError from the next-sanity/live path.

'use client'

import {isCorsOriginError} from 'next-sanity/live'
import {toast} from 'sonner'

export function handleError(error: unknown) {
if (isCorsOriginError(error)) {
const {addOriginUrl} = error
toast.error(`Sanity Live couldn't connect`, {
description: `Your origin is blocked by CORS policy`,
duration: Infinity,
action: addOriginUrl
? {
label: 'Manage',
onClick: () => window.open(addOriginUrl.toString(), '_blank'),
}
: undefined,
})
} else if (error instanceof Error) {
console.error(error)
toast.error(error.name, {description: error.message, duration: Infinity})
} else {
console.error(error)
toast.error('Unknown error', {
description: 'Check the console for more details',
duration: Infinity,
})
}
}

'use client'

import {isCorsOriginError} from 'next-sanity'
import {toast} from 'sonner'

export function handleError(error: unknown) {
if (isCorsOriginError(error)) {
const {addOriginUrl} = error
toast.error(`Sanity Live couldn't connect`, {
description: `Your origin is blocked by CORS policy`,
duration: Infinity,
action: addOriginUrl
? {
label: 'Manage',
onClick: () => window.open(addOriginUrl.toString(), '_blank'),
}
: undefined,
})
} else if (error instanceof Error) {
console.error(error)
toast.error(error.name, {description: error.message, duration: Infinity})
} else {
console.error(error)
toast.error('Unknown error', {
description: 'Check the console for more details',
duration: Infinity,
})
}
}