This release introduces zero-config usage of the SDK inside Sanity Studio, perspective-aware projections, and improved Agent Action hook documentation.
SanityApp can now run inside Sanity Studio without any manual configuration. The SDK automatically reads the active workspace's project ID, dataset, and authentication state through a new SDKStudioContext.
Before (v2.6): Studio tools required explicit configuration, even when running inside Studio.
import {SanityApp} from '@sanity/sdk-react'
const config = {
projectId: 'my-project-id',
dataset: 'production',
}
function MyStudioTool() {
return (
)
}
After (v2.7): No config is needed inside Studio. The SDK derives everything from the workspace.
import {SanityApp} from '@sanity/sdk-react'
function MyStudioTool() {
return (
)
}
Standalone apps outside Studio still pass a config prop. When both are present, the explicit config takes precedence.
Authentication is also automatic. The SDK subscribes to the Studio's token source, so Studio remains the single authority for auth and token refresh. For older Studio versions without a reactive token source, the SDK falls back to localStorage and cookie-based discovery.
studioModestudioMode is deprecated. Replace it with the new studio config property:
const config = {
projectId: 'my-project',
dataset: 'production',
- studioMode: { enabled: true },
+ studio: {},
}
useDocumentProjection now respects the active perspective (for example, 'drafts' or a release perspective) and document source. Previously, projections always queried with a 'raw' perspective and applied a manual draft overlay. Projections now follow the configured perspective directly, which means references (such as author->name) resolve correctly for drafts and releases.No code changes are required. Existing usage works the same way.
This release overhauls how you work with collections in the Media Library. The sidebar collection menu has been consolidated, adding and removing assets from collections is now optimistic, and empty collections show helpful guidance instead of a blank view.
The sidebar previously had separate "Add to existing collection" and "Add to new collection" options. These are now a single Collections submenu listing all your collections with their current state. Click a collection to add the selected assets, click again to remove them. The list scrolls when you have many collections, so it no longer overflows the viewport.
When you add or remove assets from a collection, the change now appears immediately in the UI - no waiting for a server round-trip. If something goes wrong, the change rolls back automatically. This makes organizing large batches of assets into collections feel snappy and responsive.
Empty collections now display a prompt to upload files or add existing assets. Collection cards in the grid show when they're empty, so you can tell at a glance which ones need content.
Asset thumbnails in collection cards are now larger, making it easier to identify collections by their contents at a glance. File previews in collection cards also display more cleanly, with better handling of different file types.
This release adds validation context for hidden fields, introduces a rule.skip() method, enables automatic schema extraction during development, allows documents to open with multiple split-pane views by default, and fixes several bugs including issues with scheduled drafts, timezone changes, text field updates, published document status, and the presentation tool.
Adds new context to the validation property in the schema that includes if the field is hidden (context.hidden) for any reason (be it by the hidden condition in itself or any ancestor.)
Adds new rule method rule.skip() which will skip a validation completely.
import {defineField} from 'sanity'
export const titleField = defineField({
name: 'title',
title: 'Title',
type: 'string',
validation: (rule, context) => (context?.hidden ? rule.skip() : rule.required().min(5)),
})
Schema extraction can now be performed as part of the dev and build commands. No longer necessary to run it manually.
Configure it in sanity.cli.ts as shown below.
import {defineConfig} from 'sanity'
defineConfig({
// ... rest of config
schemaExtraction: {
enabled: true
}
})
defaultPanes option to documentsNew Structure Builder API: S.document().defaultPanes(['viewId1', 'viewId2'])
Allows configuring documents to open with multiple views displayed as split panes by default. Content editors no longer need to manually set up side-by-side editing for documents where admins have configured a default split view.
// In defaultDocumentNode resolver
export const defaultDocumentNode: DefaultDocumentNodeResolver = (S, {schemaType}) => {
if (schemaType === 'article') {
return S.document()
.views([
S.view.form().id('editor'),
S.view.component(LivePreview).id('preview').title('Preview'),
S.view.component(JSONView).id('json').title('JSON')
])
.defaultPanes(['editor', 'preview']) // Form + Preview side-by-side
}
return S.document()
}
text to end up in a nested value object on the object itself.TypeError: Cannot read properties of undefined (reading 'startsWith') wasn’t very helpful, nor actionable. Good riddance! ⚡of property contains multiple primitive types that resolve to the same JSON type (e.g., both string and text). This helps developers catch configuration issues where Sanity cannot distinguish between array members at runtime.This release restores proper TypeScript typings for sanity/structure, and improves authentication handling for studios configured with auth.loginMethod: 'token' or are embedded in dashboard.
parentNode as field name.sanity@5.3.0 had a regression where structureTool(), presentationTool(), and a few other APIs ended up with any as their type, instead of the rich typescript typings that they’re supposed to have. In this release the types are back 😮💨auth.loginMethod: 'token' or embedded in Dashboard will now strictly enforce token based authentication and no longer silently fall back to cookie authentication when session cookies exist from other studios on the same domain. Similarly, studios with auth.loginMethod: 'cookie' will now ignore tokens in localStorage.This release introduces resizable panels to the Media Library, giving you more control over your workspace layout.
You can now drag the borders between the navigation sidebar, content area, and asset sidebar to customize your workspace. Panel sizes are automatically saved and persist across sessions. The Media Library also remembers layout preferences when used as a standalone app or as a plugin within Sanity Studio, so each context can maintain its own ideal configuration.
This release adds views for incoming references, automatic type generation, URL-to-link pasting in Portable Text, external studio registration, improved dialog interactions, and includes performance improvements and bug fixes for document loading and validation.
typegen to dev and build commandsThis feature adds automatic TypeScript type generation during development and build. When enabled, the Sanity CLI generates types on startup and whenever files change, providing real-time type safety for your queries.
To enable this feature, add the enabled flag to your typegen configuration in sanity.cli.ts:
export default defineCliConfig({
// ...
typegen: {
enabled: true,
// Optional: customize paths
schema: 'schema.json',
generates: 'sanity.types.ts',
},
})
typegen generate commandThe sanity typegen generate command now features a watch flag that you can use to start type generation in watch mode. It will listen for changes in the schema JSON file and files in your project.
sanity typegen generate --watch
Adds support for toggle/selected state on custom menu items in document list panes. The selected state checkmark can optionally be hidden if it’s not wanted for .menuItem in document list panes.
S.menuItem()
.title('No checkmark')
.icon(EmptyIcon)
.action(() => console.log('you clicked!'))
.params({hideSelectionIndicator: true}),
You can also read the params to check in an .action() in a .menuItem whether the action is selected or not in document list panes.
S.menuItem()
.title('View Mode: Default')
.icon(DocumentIcon)
.group('view')
.params({value: 'default'})
.action((params) => console.log('default', params?.isSelected, params)),
Users can now register externally-hosted studios with the --external flag:
sanity deploy --external
This registers the studio URL without building or uploading assets, enabling features using the studio manifest for studios hosted on custom infrastructure.
To unregister an external studio:
sanity undeploy
For external studios, this uses “unregister” terminology and does not warn that the hostname will become available (since you control the external URL).
Note: External studio deployment requires a sanity.config.ts.
You can now see which documents reference the active document without creating a custom document view.
When viewing a document:
This opens a side pane with the incoming references by type.
In addition to the incoming references panel, developers can also embed an incoming reference decoration alongside other fields in the document. This involves updating the document schema by using the new renderMembers functionality.
To get started, see the incoming reference field documentation.
pasteLink plugin enabled by defaultPasting a URL in a Portable Text Input now automatically creates a link.
disableNew option for image fieldsNew disableNew option for image and file fields - when enabled, hides the upload UI while preserving the ability to select existing assets from the media library. Useful for centralized asset management workflows where teams want to prevent ad-hoc uploads and enforce selection from a curated library.
When viewing a content release, it’s now possible to filter the list of documents in the release by whether they have validation errors or by release action type (unpublish, add, or change).
Fieldgroup tabs will now show a validation status icon to indicate if any fields in that group needs attention.
path to ConditionalPropertyCallbackContextAdds path to ConditionalPropertyCallbackContext allowing users to hide or disable fields according to the path they are in.
import * as PathUtils from '@sanity/util/paths'
import { defineType} from 'sanity'
export const conditionallyHiddenField = defineType({
name: 'conditionallyHiddenObject',
type: 'object',
title: 'Conditionally Hidden Object',
description: 'Object with a conditionally hidden field',
fields: [
defineField({
name: 'title',
type: 'string',
title: 'Title ',
description: 'Title (hidden if path starts with "hiddenTitles")',
hidden: ({path}) => {
if (PathUtils.startsWith(['hiddenTitles'], path)) {
return true
}
return false
},
}),
defineField({
name: 'description',
type: 'string',
title: 'Description',
}),
],
})
Click outside of an object dialog to close all of the dialogs in a single go.
We're excited to announce official GitHub Actions for Sanity Blueprints, making it easier than ever to automate your Blueprint deployments and review changes in your CI/CD pipeline. As part of this update, we’ve also removed the personal auth token limitation. You can now officially deploy your blueprint stacks with robot tokens.
Automatically deploy your Sanity Blueprints to your project or organization directly from GitHub Actions. Perfect for continuous deployment workflows that trigger on merges to main or specific branches.
name: Deploy Sanity Blueprints
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy blueprints
uses: sanity-io/blueprints-actions/deploy@deploy-v2
with:
sanity-token: ${{ secrets.SANITY_TOKEN }}
stack-id: 'ST_1234xyz'
project-id: '1234xyz'
Preview Blueprint changes before they're deployed. This action analyzes your changes and automatically posts (or updates) a comment on your pull requests showing exactly what resources will be created, updated, or deleted.
name: Sanity Blueprints Plan
on:
pull_request:
permissions:
contents: read
pull-requests: write # Required for posting comments
jobs:
plan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Plan blueprints changes
uses: sanity-io/blueprints-actions/plan@plan-v1
with:
sanity-token: ${{ secrets.SANITY_TOKEN }}
stack-id: 'ST_1234xyz'
project-id: '1234xyz'
The plan action comment gives you a preview of what to expect when prior to deployment.
Check out the new guide to set up the actions and start building your workflows. For questions and support, visit the Sanity community or open an issue in the repository.
This month we've added additional mutation documentation, reorganized our Functions and AI sections for easier navigation, and introduced quick start guides for content operators.
We’ve added a new collection of articles, and updated existing ones, to better explain how to mutate documents in your Sanity datasets.
HTTP reference documentation now includes more links to usage guides where available, as well as more specific permission requirements.
Our Content Ops team created quick start guides to help writers, editors, and other members of your content ops teams find their way in Studio and Media Library more easily.
We’ve split the old Compute and AI section up. Some articles have moved to other sections, but larger concepts now have their own space. The Functions section also includes updates to the quick start guide to be quicker and more agent-friendly, and we’ve added a guide specific to Media Library Asset Functions.
You may have seen Sanity’s announcements about MCP servers and Agent Toolkits. These, along with future features, now live in the Build with AI part of the docs. Keep an eye out for much more soon.
You can find these new sections in under the “Platform” menu in the top navigation. These changes should make finding what you need easier as these feature areas continue to grow.
The changelog tab on documentation articles now shows a “new” badge if they are affected by any changelog entries in the last 30 days.
We’ve also improved the in-article changelog layout to better fit the article’s reduced screen space.
Previously you could add .md to articles, but now sections and changelog entries support Markdown URL variants.
Thanks to Matthew Ritter for the contribution.
The cookie consent management experience has been refined across the documentation site for clearer choices and a smoother UX.
We've enhanced Sanity Functions with automatic system logging that gives you better visibility into why your functions are or aren't running. The runtime now injects system logs directly into your function's log stream for key operational events.
Previously, when a function didn't run, it could be unclear why. Was it rate limited? Did it hit a recursion limit? Was the project over quota? You'd need to reach out to support channels to understand what happened.
Your function logs now include system-generated messages for important runtime events like rate limiting, quota exhaustion, and recursion blocking. These logs appear alongside your function's own console output, making it easier to diagnose issues without having to reach out to support.
The system automatically logs the following events:
When viewing your function logs in the CLI (npx -y sanity@latest functions logs --watch) or in your project dashboard, system messages appear with color-coded severity levels:
2026-01-28 23:00:00.000 INFO Function invocation started
2026-01-28 23:00:01.000 WARN Maximum recursion depth exceeded: function invocation blocked
2026-01-28 23:00:02.000 WARN Quota exceeded: function invocation blocked
2026-01-28 23:00:03.000 WARN Rate limit exceeded: function invocation blocked
2026-01-28 23:00:04.000 ERROR Function invocation failed
state=all.This update ensures Studio field filters are now applied to collections and recent upload sessions when picking an asset, and refines the asset metadata UI to make it easier to read long values and large lists of metadata.
It also introduces the ability to bulk edit array fields, sort assets in the asset grid, and includes a selection of bugfixes around asset visibility/private assets.
Studio field filters are now applied to collections and recent upload sessions when picking an asset, to hide irrelevant collections and upload sessions if they don't contain assets suitable for the field.
When bulk editing multiple assets, you can now edit array fields. The form displays only items that are common across all selected assets. Items unique to individual assets won't appear, but you'll see a prompt to reset the field across all assets if needed.
From there you can:
The asset metadata UI is now left-aligned and allows long values to wrap:
Assets can now be sorted by:
Note: sorting for search results is not currently supported.
When selecting text in the Portable Text Editor with multiple overlapping annotations (e.g., a link that is also formatted as inline code), the editor now shows a single combined popover with one row per annotation, instead of multiple overlapping popovers.
Copy/paste now works correctly for arrays with anonymous objects (inline object definitions without a name). Previously these would fail with a type mismatch error.
Copy/paste now preserves empty marks and markDefs arrays in Portable Text blocks. Previously these fields were incorrectly stripped during paste operations.
Validation inspector now correctly displays path titles for anonymous objects in arrays.
Adds the ability to clear radio field selections via a new Clear button.
Clicking the Close button in a dialog for a nested object input will now step incrementally backwards through the nested structure before finally closing the whole dialog.
Example: with an object with the following breadcrumb Animals / #1 Shark / Description / Item: [{Content: ... when pressing the x at the top right:
Before: the whole dialog would close.
After: the dialog will remain open with Animals / #1 Shark in focus.
Self-updating studios now flag the correct latest available version for upgrading.
Pasting content copied from a Portable Text input will now result in clean plain text or semantic HTML depending on what the destination input expects.
@ to find document references in the connected studioThis release introduces configurable logging for the Sanity SDK, giving you visibility into SDK operations during development and troubleshooting.
You can now configure logging to control what messages appear and from which parts of the SDK. This is useful for debugging authentication flows, document operations, and other SDK behavior.
import {configureLogging} from '@sanity/sdk'
configureLogging({
level: 'info',
namespaces: ['auth', 'document']
})
The logger supports five levels of verbosity:
error: Critical failures that prevent operation.warn: Issues that may cause problems but don't stop execution.info: High-level informational messages.debug: Detailed debugging information.trace: Very detailed tracing, including internal stream operations.Set namespaces to control which functional areas produce logs. Use ['*'] to see everything.
sanity-groq rule accessible via get_sanity_rules. GROQ patterns and guidance are now part of the unified rules system.