Configure your Media Library with an SDK config app
All the information needed to start configuring the Dashboard 2.0 version of Media Library with a config app.
Beta API
The Dashboard extension API is in beta. Functions prefixed with unstable_ can change without notice.
Aspects are the custom fields you add to assets in Media Library, such as descriptions, credits, SEO metadata, or locations. Previously, aspect definitions were limited to basic field types, without support for validation, initial values, or custom components.
You can now define aspects in code using a config app: a small app without a user interface, whose sole purpose is to define your Media Library's aspects. Each aspect is defined using defineField, the same API and feature set used for Studio schemas. You then deploy the app using the Sanity CLI.
Once deployed, the config app becomes the source of truth for your Media Library's custom fields across the Sanity Dashboard 2.0 ecosystem.
Prerequisites
- A Sanity organization with Media Library enabled, and membership of that organization.
- The
sanity/cli@8.23.0or above - Understanding the basics of how applications work in Dashboard 2.0.
Create a config app
By using the init command in the CLI with the media-library-config template we will bootstrap everything you need to get started.
sanity init --template media-library-configCreate a restore point with Git or a backup
Once you've initialized your config app and added your existing aspect definitions as code, it's a good idea to make an initial Git commit or create a backup. This gives you a starting point you can easily return to if needed.
If you previously have defined and deployed aspects for your Media Library, you will be asked if you want to use these as a starting point for your configuration app. We will turn them into the required code needed to have parity with your current Media Library’s aspects. You can then develop, preview and finally deploy the new fields to the new Dashboard version of the Media Library.
Backwards compatibility
When you configure and deploy a Media Library config app, your existing Media Library (in the current Dashboard) will continue to work as before, unless you explicitly change the underlying field definitions (such as names or types).
In Dashboard 2.0, Media Library will continue to use your existing aspect definitions until you deploy a config app.
What a configuration looks like
import {defineCliConfig, unstable_defineMediaLibrary} from 'sanity/cli'
export default defineCliConfig({
app: unstable_defineMediaLibrary({
organizationId: '<your-organization-id>',
fields: [
{name: 'description', title: 'Description', src: './src/fields/description.tsx'},
{name: 'seo', title: 'SEO', src: './src/fields/seo.tsx', public: true},
],
}),
})Each entry in fields becomes one aspect:
srcpoints at a module whose default export is adefineField(...)definition.namemust be the same as thenameinside thatdefineField(...). Asset values are stored under that name, so a mismatch leaves the aspect unable to find its data.- The title people see in Media Library comes from the
defineField(...)definition, not from the entry'stitle. public: truemarks the aspect as public, the same way as before.
Every aspect needs a unique name. If two fields share a name, you will get a error message when running sanity dev or sanity deploy.
Define fields
Field modules are ordinary Studio field definitions. Your fields configuration runs live in the Dashboard 2.0 version of the Media Library, because Media Library loads your field modules rather than a copy of them.
Previewing your changes
While you develop on your fields, you can live preview them in your Dashboard 2.0 version of the Media Library by running the config app locally. You do this by running sanity dev from your configuration app root.
sanity devValidation
import {defineField} from 'sanity'
export default defineField({
name: 'description',
title: 'Description',
type: 'text',
validation: (rule) => rule.required().max(500),
})Validation messages appear next to the aspect's title in the asset sidebar.
Validation that depends on the asset
context.document is the whole asset document, so a rule can depend on the asset's other properties:
validation: (rule) =>
rule.custom((value, context) => {
const isPublicAsset = context.document?.cdnAccessPolicy === 'public'
return isPublicAsset && !value?.holder ? 'Public assets need a copyright holder' : true
}),Default values
An aspect's initialValue is applied once, right after an asset is uploaded. It never overwrites a value someone has already entered. It can be a value or a function, including an async one:
initialValue: () => ({year: new Date().getFullYear()}),Only the aspect's top-level initialValue is applied. Put defaults on the aspect itself, not on its nested fields.
Defaults from the uploaded file
initialValue functions receive the uploaded asset and its file metadata as their second argument. For example, to pre-fill a location from a photo's EXIF GPS data:
initialValue: (_params, context) => {
const location = context?.instance?.metadata?.location
return location ? {lat: location.lat, lng: location.lng} : undefined
},defineField TypeScript types don't declare this second argument yet, so in TypeScript you'll need to type context yourself and cast the function.
If an initialValue function throws, that aspect is left empty; the upload and other aspects are unaffected.
Conditional fields
hidden works the same way as in Studio. document is the whole asset document, so you can show an aspect for only one asset type:
hidden: ({document}) => document?.assetType !== 'sanity.imageAsset',assetType is sanity.imageAsset, sanity.videoAsset or sanity.fileAsset.
Custom input components
Write custom inputs exactly as you would for Studio:
import {set, unset} from 'sanity'
import {TextInput} from '@sanity/ui'
function NotesInput(props) {
return (
<TextInput
value={props.value ?? ''}
onChange={(event) => {
const next = event.currentTarget.value
props.onChange(next ? set(next) : unset())
}}
/>
)
}
export default defineField({
name: 'notes',
title: 'Notes',
type: 'string',
components: {input: NotesInput},
})Each custom input runs on your config app's own React, sanity and @sanity/ui versions, isolated from Media Library. Media Library updates never require you to rebuild or redeploy.
Inside a custom input you can use these patch functions and hooks from the sanity package:
Patch functions | Hooks |
|---|---|
|
|
|
|
|
|
|
@sanity/ui components work and follow the Dashboard 2.0 theme.
renderDefault works for simple field types.
These aren't available inside Media Library:
- Workspace hooks such as
useClient,useCurrentUseranduseWorkspace. renderDefaultfor objects and arrays.PatchEvent. Callprops.onChangewithset,unsetorsetIfMissingpatches instead.
If a custom input fails to load or crashes, Media Library shows a "This field couldn't be loaded" message in its place, and the rest of the form keeps working.
Using window globals and similar in custom components
You can bundle npm dependencies, such as a map library. Put components that use browser-only libraries in their own module and load it lazily from your field module, so the field module itself can be imported without a browser.
Deploy your config
sanity deployOnce deployed, the config app's fields replace your Media Library's aspects in the Dashboard 2.0 and current version of Media Library.
Removing or drastically changing a previously available aspect fields from the config removes or changes it from both versions of the Media Library (current and Dashboard 2.0 version). You will be prompted to confirm ‘yes’ by the deploy command if you are removing a field that’s currently in use in the current version of the Media Library.
Modifying or removing deployed aspects
Values already stored on assets are preserved even if the corresponding aspect or field is removed or changed. If you add a removed field back, its previously stored values will reappear in the editor.
It's a good idea to keep a backup of your previous definitions (for example, in Git history) so you can restore them if something unexpected happens.
Remember that you can always preview your updated configuration in the Dashboard 2.0 Media Library by running sanity dev. This lets you test your changes without affecting the deployed configuration until you run sanity deploy.
Was this page helpful?
Feedback submitted, thanks for helping us improve the docs. Have you tried these alternatives?