Extension API reference
Reference for defineApplication, the view and web worker helpers, unstable_defineView, unstable_defineService, and unstable_defineMediaLibrary.
The Dashboard extension API declares a Dashboard application, the views it shows, and the web workers it runs. Call the configuration helpers in sanity.cli.ts. Use the runtime helpers as the default export of each view or web worker source file.
Beta API
The Dashboard extension API is in beta. Functions prefixed with unstable_ can change without notice.
Imports
sanity/cli:defineApplication,definePanelView,defineWindowView,defineTileView,defineAssetSourceView,defineWebWorker, andunstable_defineMediaLibrary.sanity/dashboard:unstable_defineViewandunstable_defineService.
defineApplication
Declares the application. Assign the result to app in defineCliConfig.
import {defineApplication, defineCliConfig, definePanelView, defineWebWorker} from 'sanity/cli'
export default defineCliConfig({
app: defineApplication({
organizationId: 'your-organization-id',
slug: 'my-app',
name: 'my-app',
title: 'My app',
entry: './src/App.tsx',
views: [definePanelView({name: 'inbox', title: 'Inbox', src: './src/panel.tsx'})],
webWorkers: [defineWebWorker({name: 'sync', title: 'Sync', src: './src/worker.ts'})],
}),
})RequiredorganizationId
string
ID of the organization that owns the app. The app runs in and deploys to this organization's Dashboard.
Requiredslug
string
Application address and the hostname it deploys to. Use lowercase letters, numbers, and hyphens. Start with a letter and end with a letter or number.
Requiredtitle
string
Label shown on the Dashboard dock button. Overrides the
titleinsanity.config.ts.name
string
Stable application identity. Defaults to
slug. Set it explicitly so that renamingslugdoesn't change the app's identity. Uses the same format asslug.entry
string
Path to the App SDK entry file, for example
./src/App.tsx. Creates the app's navigable window. Omit it for an app that only exposes views and web workers. Studios get their window automatically and don't acceptentry.icon
string
Path to an SVG shown on the dock button. Overrides the icon from the app manifest or Studio configuration.
dock
{group, order}
Default dock placement for the app's window and its panel and window views.
groupissystem,applications, oruser.ordersorts ascending within the group; anything without anordersorts as100.views
array
Views the app exposes. Create each entry with
definePanelView,defineWindowView,defineTileView, ordefineAssetSourceView.webWorkers
array
Background web workers the app runs. Create each entry with
defineWebWorker.visibility
default | unlisted | disabled
Dashboard visibility. Defaults to
default.
name must be unique across the app's window, its views, and its web workers. The app's window uses the app name, or slug when name is omitted.
Validation errors
The CLI validates defineApplication when it starts, builds, or deploys the app. It reports these errors:
App `organizationId` is required — pass the owning organization's ID to `defineApplication`App `slug` is required — the hostname the application is created at on deployApp `slug` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric`name` must be unique across views and web workers. Rename one of the duplicates.App views for studios are not implemented yet
View helpers
Each helper sets the view's surface. Add the result to views in defineApplication. Every view takes these fields:
Requiredname
string
Identifies the view. Must be unique within the app. Use letters, numbers, hyphens, and underscores.
Requiredtitle
string
Display title.
Requiredsrc
string
Path to the view's source file. For panel, tile, and asset source views, the file default-exports
unstable_defineViewfor the same surface.
definePanelView({name, title, src, dock}): Declares a dock panel.dockis optional and overrides the app-leveldock.defineWindowView({name, title, src, dock}): Declares a window.dockis optional and overrides the app-leveldock.defineTileView({name, title, src, size, order}): Declares a Dashboard tile.sizeis required and issmall,large, orbanner.orderis optional and sorts tiles in ascending order.defineAssetSourceView({name, title, src}): Declares an asset source picker.
defineWebWorker
Declares a background web worker. Add the result to webWorkers in defineApplication. It takes name, title, and src, with the same rules as view fields. The src file default-exports unstable_defineService.
unstable_defineView
Import unstable_defineView from sanity/dashboard and use the result as the default export of a view's src file. The first argument is the surface. The second is the components for that surface.
import {unstable_defineView} from 'sanity/dashboard'
export default unstable_defineView('panel', {
title: ({view}) => <>{view.title}</>,
panel: ({view}) => <p>Content for {view.name}</p>,
})panel:{title, panel}. Each component receivesview, which contains the view'snameandtitle.tile:{tile}. The component receivesview, which contains the tile'sname,title, andsize, so the tile can render for its footprint.asset_source:{asset_source}. The component receives the same props as a Studio asset source component (AssetSourceComponentProps).
Each component renders in its own island and doesn't inherit the Dashboard's context or providers. Wrap it in SanityApp from @sanity/sdk-react before using App SDK hooks.
import {unstable_defineView} from 'sanity/dashboard'
export default unstable_defineView('tile', {
tile: ({view}) => (view.size === 'banner' ? <h2>{view.title}</h2> : <p>{view.title}</p>),
})unstable_defineService
Import unstable_defineService from sanity/dashboard and use the result as the default export of a web worker's src file. The first argument is the service type; worker is the only type. The callback runs once when the worker starts and receives bus and service. service contains the worker's name and type. Return a cleanup function for timers, listeners, and connections.
bus is the Dashboard message bus, scoped to the views of the same app:
bus.emit(topic, payload): send a message. Emitworkers.messageto reach the app's views.bus.query(stateTopic): read a state topic's current value.bus.subscribe(stateTopic, handler, {signal}): listen to a state topic. Subscribe toworkers.postto answer a view's post. Each message arrives as{name, payload}and carriesreplyandreject.
import {unstable_defineService} from 'sanity/dashboard'
export default unstable_defineService('worker', ({bus, service}) => {
const controller = new AbortController()
bus.subscribe(
'workers.post',
(message) => message.reply(`${service.name} is running`),
{signal: controller.signal},
)
return () => controller.abort()
})