Studio workflow improvements, add metadata to releases, and bug fixes
Published: October 28, 2026
This release adds custom metadata fields to content releases when using variants beta, moves version management to a document inspector for variants users, improves breadcrumb navigation and field interactions, fixes search functionality issues, and enhances overall stability with better loading states and error handling.
Download the schema from the diagnostics dialog
The Studio diagnostics dialog can now download the workspace schema to share with Sanity support.
Add configurable metadata fields to release forms
For Content Variants beta users, Studios can add extra fields to content releases with releases.metadata.fields when beta.variants is enabled, coming soon to the rest of studios. The definitions are the same defineField calls used in Structure. They appear on the create-release form and in the edit-release dialog. They do not appear in the inline editor, which is the release detail surface when variants are off. Empty config changes nothing.
beta: {
variants: {enabled: true}
},
releases: {
metadata: {
fields: [
defineField({
name: 'legalReview',
title: 'Legal review',
type: 'string',
initialValue: 'notReviewed',
options: {
list: [
{title: 'Not reviewed', value: 'notReviewed'},
{title: 'Reviewed', value: 'reviewed'},
],
},
}),
],
},
}Allowed resolved types are string (including an options list), text, number, boolean, date, datetime, url, and object whose own fields are allowed. reference, crossDatasetReference, image, file, Portable Text, array, and anything else are dropped with a development warning. Field validation rules run, and create or save is blocked while a field has an error or while its check is still running. initialValue is applied once on create. Clearing a field removes the key.
Field-level component overrides (components.input, components.field, and the other components keys) are intentionally unsupported for now. They can be added later without changing releases.metadata.fields.
These fields are not shown on the release detail page, on scheduled drafts, or in the releases table.
Move version management to document inspector
For Content Variants beta users, version management now lives in a document inspector. Open it with the "Manage versions" action in the document panel header. The inspector gives the interface more room and lets editors share a link directly to the version list.
🐛 Notable bugfixes and improvements
- Breadcrumbs in nested object and array item dialogs now do what their label suggests. Clicking a field name scrolls to that field and focuses it, and clicking an item (a dialog title) scrolls that dialog back to the top. Clicking the title of the dialog that is already open no longer closes it.
- Collapsible fieldsets and collapsible object fields can now be expanded or collapsed by clicking anywhere in their header row, not just the title.
- Vision no longer shows its Variant option, nor sends a variant with queries, in workspaces where variants are switched off (
beta.variants.enablednot set), matching the rest of the studio, which shows no variant selector there either. - Arrays that use the grid layout no longer force nested arrays to render as grid tiles. A nested array keeps its own item component and custom input, including inside an image dialog opened from a grid.
- Every field and array item gets its own loading boundary again. If a custom form component (
components.input,components.field,components.item, or a plugin'sform.components) suspends, for example on an App SDK hook such asuseDocumentProjectionfor a document that has not been created yet, only that field or array item shows a loading skeleton, instead of the whole document form staying on "Loading" (a regression in 6.17.0). Studio also logs a console warning naming the component, field path and document type, explaining how to add aSuspenseboundary whose fallback reserves the component's space, so the form does not shift when it loads. - Studio search no longer fails with
score() function received unexpected expressionwhensearch.unstable_partialIndexing.enabledis on and the dataset's partial index excludes a field that search would boost, such as a preview title, or when a slug field sits at the dataset's maximum field depth. Those fields are no longer boosted, and matching documents are still returned. - In a release's document list, Unpublish and Discard version now name your roles when you do not have permission to use them, matching the document footer.
- Fixes Content Agent proposed changes not loading in a Studio inside Workbench when the page origin isn't a CORS origin with credentials on the project.
- Fixes a crash in the Structure tool after reloading or switching perspectives while an array item whose
_keycontains a period or a closing bracket was open. - Studio search no longer lists Content Agent document versions when querying across all versions. Those versions were often duplicates of the real document and opened as an empty document for anyone who was not the author.
- The Reload button on the structure tool's error screen now reloads only the structure tool instead of the whole page. It retries the structure; picking up a newly deployed Studio still needs a page reload.
- Review changes now shows the same calendar day that is stored on a date field. Previously, in timezones behind UTC, the diff could show the previous day.
sanity schema extract --watchnow re-extracts when you edit your schema orsanity.configfile. Previously, it ran the first extraction and then never ran again, without reporting an error.sanity typegen generate --watchnow works withtypegen.resources(beta). Previously, the command exited with "Watch mode does not support typegen.resources yet". A change to any resource's query files or local schema file regenerates every resource. A resource without a localschemauses the schema deployed to its dataset, which is fetched once when the watcher starts, so restart the watcher to pick up a newly deployed schema.- New
sanity codemod dashboardcommand moves an existing Studio or SDK app onto the Dashboard. It rewritessanity.cli.tsto wrapappindefineApplication, looks up the organization from the project, and prompts for a title and slug. The existing deployment stays live. The codemod warns whendeployment.appIdwould make the first Dashboard deploy overwrite the existing app, and when the installedsanityversion is too old fordefineApplication. sanity codemodno longer ends every run with anExitErrorstack trace, even successful ones. It now waits for the codemod to finish and exits with its exit code, so a failed run is reported as a failure.sanity tokens createcan now create organization tokens, the same kind of token the Add API token dialog in Manage creates. One token can hold organization permissions (such as Context, Blueprints, and Media Library) and roles on several projects. Interactive runs show a single checklist of everything the token can access, then print the equivalent flags for use in CI, for examplesanity tokens create ci --grant context=developer --grant project:<projectId>=editor. Existing--project-idand--roleusage still creates a project token. Unattended runs with no grant and no project now fail with a usage error (exit code 2) instead of exit code 1.sanity tokens listandsanity tokens deleteaccept--organization <id>, so you can find and revoke organization tokens from the CLI.- New
sanity whoamicommand prints the user or API token the CLI is authenticated as: name, email, ID, login provider, and where the token came from (the CLI config file, theSANITY_AUTH_TOKENenvironment variable, or the CLI execution context). SAML SSO logins also show the organization. Pass--jsonfor machine-readable output. The command exits with code 1 when you aren't logged in. - Commands that support
--jsonnow return argument and runtime errors as JSON, and exit with a nonzero code when they fail. Successful responses keep their existing shape, and-jaliases still work. In help output,--jsonnow appears with the global flags. sanity deploynow refuses to deploy a Studio that is referenced by a Blueprint, and tells you to deploy it withsanity blueprints deployinstead.- The Dashboard links that
sanity deployandsanity undeployprint, including in dry runs and--jsonoutput, now use the app or Studio's configured slug instead of its application ID. Deployments without a slug still link by ID. - For Dashboard apps without an app view (panel-only apps),
sanity deployand its dry run now link to your organization's Dashboard. Previously, they printed an/applications/<slug>URL that returned a 404. - Background services in Dashboard apps can now respond to event topics.
bus.subscribe(topic, (message) => message.reply(value))works in a worker as it does on the page, so a worker can answer requests from its app's views. sanity deploynow uses the federation manifest from the build it just ran, and reads it from the output directory only when the build is skipped. A federated build that doesn't write a federation manifest now fails with an error naming the missing file.