Portable TypeGen types, keepPanesOnCreate for Structure, and diagnostics upgrades
Published: September 8, 2026
This release makes TypeGen query result types work across every copy of @sanity/client without workarounds, adds an opt-in keepPanesOnCreate option to the Structure tool, and reports styled-components details in Studio diagnostics. Headless validation gains cancellation and capability-aware results, and fixes land for Safari 17 cancellation errors, idle re-renders, and several UI quirks.
Keep panes when creating from a nested pane
The structure tool takes a new opt-in option, keepPanesOnCreate:
import {structureTool} from 'sanity/structure'
export default defineConfig({
// ...
plugins: [structureTool({structure, keepPanesOnCreate: true})],
})With it enabled, creating a document from a pane's own "create" button keeps the navigation panes visible instead of replacing them with a single document editor. The new document opens as that pane's child, and the panes before it collapse when there is not enough room, the same behavior as opening an existing document from a list. This matters most for structures built as trees, where the pane path is the editor's only indication of where in the tree they are working.
It applies only to create actions offered by a pane that is currently open, matched on both the initial value template and its parameters. Deep links, reference links, and create actions for a type that no open pane offers are unaffected and still navigate to the matching location in the structure. The option defaults to off, so nothing changes unless you enable it.
Limitations: an edit intent that matches nothing in the structure still replaces the pane path; and with split panes open, panes that would otherwise close can remain in the path.
styled-components details in Studio diagnostics
The Studio diagnostics dialog (help menu → Diagnostics, and the copied JSON report) gains a styled-components card when styled-components is on the page: the versions in use, the number of <style data-styled> sheets with a caution badge when there is more than one (a plugin shipping its own copy), and the number of CSS rules those sheets hold. The Studio card also reports whether the studio is auto-updating. In the JSON these appear as styles.styledComponents (one {ruleCount, version} entry per sheet) and studio.autoUpdates.
TypeGen: query result types work across every copy of @sanity/client
sanity typegen generate now registers each query's result type on a global SanityQueries interface instead of augmenting the @sanity/client module. The tail of the generated file changes from
// Query TypeMap
import "@sanity/client";
declare module "@sanity/client" {
interface SanityQueries {
'*[_type == "post"]': PostsQueryResult;
}
}to
// Query TypeMap
declare global {
interface SanityQueries {
'*[_type == "post"]': PostsQueryResult;
}
}
// Lets @sanity/client releases that predate the global registry read it too
declare module "@sanity/client" {
interface SanityQueries extends globalThis.SanityQueries {}
}The global registry does not depend on module resolution, so typed client.fetch(query) results from @sanity/client, and typed sanityFetch({query}) results from next-sanity's defineLive, no longer require the generated file to resolve the exact same @sanity/client .d.ts as the rest of your code. In practice this means:
- Monorepos and strict pnpm layouts: you no longer need
@sanity/clientas a direct dependency of the package that holds the generated types file, and you no longer needpnpm.overrides, Yarnresolutions, or npmoverridesto force a single@sanity/clientcopy just to get typed fetches. next-sanity: the@sanity/clientcopy thatnext-sanitynests under itself reads the same registry as your app's copy, sosanityFetchis typed without workarounds. Shims like thesanity.next-sanity.d.tsfrom the Next.js personal website template (declare module 'next-sanity' { interface SanityQueries extends ClientSanityQueries {} }) can be deleted.@sanity/client/stega:ClientReturnStegaand stega-enabledclient.fetchcalls pick up the generated types as well, including on the 7.x line.
How to get it: upgrade sanity and run sanity typegen generate again. Nothing changes in sanity-typegen.json or in how you call the command. To benefit across multiple client copies, make sure each installed @sanity/client is 8.5.0+ or 7.27.0+ (for example pnpm update -r @sanity/client or npm update @sanity/client); a fresh lockfile picks these up automatically since they are in-range for ^8 and ^7.26.
Compatibility:
- Existing generated files that use the old
declare module '@sanity/client'form keep working unchanged. - Older
@sanity/clientreleases (6.21.0 and up) still work through the bridge line, but only for the one copy the generated file resolves, exactly as before. - This is about the types of query results. Passing a client instance created by one
@sanity/clientcopy into an API typed against another copy (for example handing a root@sanity/clientinstance todefineLivewhilenext-sanitynests its own client) is still aSanityClientclass mismatch; create that client withcreateClientfromnext-sanityinstead, as the official templates do. - The generated file no longer begins with a side-effect
import "@sanity/client". If@sanity/clientcannot be resolved from the generated file at all, a.tsoutput now reportsTS2664on the bridge line (previouslyTS2307on the import undernoUncheckedSideEffectImports); pointinggeneratesat a.d.tspath avoids the error, since TypeScript skips ambient augmentations of unresolvable modules, and the global registry still types the installed client. - The generated file still has to be part of your TypeScript program (covered by
includeintsconfig.json), as before.
Headless validation: cancellation and capability-aware results
Headless and workspace validation now accept signal. Aborting rejects with signal.reason (or AbortError) and cancels pending validation and network work.
The headless @sanity/validation.validateDocument() returns {status, markers, skipped} and accepts an optional client plus customValidation. Use {client: undefined, customValidation: false} for guaranteed no-network structural validation. The validateDocument export from the sanity package is unchanged.
🐛 Notable bugfixes and improvements
- Fixes document validation and other concurrency-limited client fetches failing on Safari 17.0–17.3 with
TypeError: AbortSignal.any is not a function. Cancellation now works on those Safari releases and continues to use the browser's nativeAbortSignal.anyeverywhere else. - Sanity Studio no longer re-renders parts of the UI while idle. Presence heartbeats from other collaborators and the periodic cross-dataset reference check previously caused continuous re-renders in every open studio tab, and typing in documents with advanced version control enabled recomputed divergence navigation state on every keystroke. No API changes.
- The Draft perspective chip in the document header now stays orange when the document is published and has no draft. Previously the badge inherited the published (green) color.
- Portable Text annotation edit popovers that contain a reference field now use the same ~640px width as the PTE column, and the reference search results list can show several documents at once instead of a single cramped row.
- Fixes a bug that could cause the "This reference has changed since you opened it." banner to flicker erroneously, especially when the client's connection is slow.