App lookups by slug and custom API hosts
Published: October 27, 2026
Version 3.10.0 adds two capabilities you can reach for in your own apps: looking up an application by its slug within an organization and sending project requests to an API host that doesn't use a project subdomain.
Look up an application by its slug
useApplication and the application fetcher accept an application's id or its slug. A slug is only unique within an organization, so pass an organizationId alongside it. Results are cached per organization, so the same slug in two organizations resolves to two different applications. The include tokens still shape the returned type.
import {useApplication} from '@sanity/sdk-react'
export function StudioCard() {
const {data: studio} = useApplication('my-studio', {
include: ['config.studio'],
organizationId: 'org_1',
})
return <h2>{studio.title}</h2>
}Send project requests to an API host without a project subdomain
Project requests, such as queries, documents, users, and presence, go to <projectId>.<apiHost> by default. The new useProjectHostname option on SanityConfig turns that off, so requests go to auth.apiHost as-is. Set it to false when the host already identifies the project, for example a Content Lake-compatible proxy served under a path. Global, Media Library, and Canvas requests never use the project subdomain, and the option reaches users, presence, datasets, and addon datasets too.
import {createSanityInstance} from '@sanity/sdk'
const instance = createSanityInstance({
projectId: 'abc123',
dataset: 'production',
// The host already identifies the project, so skip the project subdomain
useProjectHostname: false,
auth: {apiHost: 'https://example.com/api/document/abc123'},
})Studio links follow a workspace's base path
urlFor.studios(id).workspace() now takes the workspace itself, or any object with its basePath, and links to that path instead of the workspace's name. A workspace with a null base path is the studio's root, so a single-workspace studio named default at / links to the studio root rather than to /default. useNavigateToStudioDocument uses the base path too, and opens the studio at its slug, so a document opens in the workspace you meant.
import {urlFor} from '@sanity/sdk-react/dashboard'
// Before: built from the workspace's name
urlFor.studios(studio.id).workspace(workspace.name)
// Now: takes the workspace and links to its base path
urlFor
.studios(studio.id)
.workspace(workspace)
.intent('edit', {id: documentId, type: documentType})
.url()
// '/studios/<studio id>/<base path>/intent/edit/id=<id>;type=<type>/'🐛 Notable bugfixes and improvements
- Projection results from
useDocumentProjection,getProjectionState, andresolveProjectionnow type the_statusfield the SDK adds to every result, andDocumentStatusis exported for typing it. - Checking permissions on a document the user cannot read fails with the read error instead of loading forever.
- Reads, user lookups, and releases that failed with a 401 retry once the token changes, and network, 408, 429, and 5xx errors are retried before the SDK reports an authentication error.
useDocumentProjectionkeeps its subscription when a component re-renders with a handle that has the same values, such as handles from a refetcheduseDocumentslist.- Auto-updating apps can load
@sanity/sdkand@sanity/sdk-reactsubpaths from the module CDN again.