# App lookups by slug and custom API hosts

**Version:** v3.10.0

**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.

**StudioCard.tsx**

```tsx
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.

**instance.ts**

```ts
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.

**studioUrl.ts**

```ts
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`, and `resolveProjection` now type the `_status` field the SDK adds to every result, and `DocumentStatus` is 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.
- `useDocumentProjection` keeps its subscription when a component re-renders with a handle that has the same values, such as handles from a refetched `useDocuments` list.
- Auto-updating apps can load `@sanity/sdk` and `@sanity/sdk-react` subpaths from the module CDN again.

