
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeIn Sanity Studio v3, you don't need to worry about plugins overwriting each other's document actions - the system handles composition automatically! When you add multiple plugins or define multiple actions, they all get combined into the actions menu.
Here's how it works:
When you register document actions in your sanity.config.ts, you can provide either a static array or a resolver function. If you want to add actions from multiple sources (your own custom actions plus the defaults), use the resolver function approach:
import {defineConfig} from 'sanity'
import {FirstCustomAction} from './first-action'
import {SecondCustomAction} from './second-action'
export default defineConfig({
// ... rest of config
document: {
actions: (prev, context) => {
// prev contains all previously registered actions (from plugins and defaults)
// Just add your new actions to the array
return [FirstCustomAction, SecondCustomAction, ...prev]
},
},
})The prev parameter contains all actions that have been registered before yours - including actions from plugins and the Studio defaults (publish, duplicate, delete, etc.). By spreading ...prev into your returned array, you preserve all existing actions while adding your new ones.
If you're creating separate plugins that each add document actions, they compose automatically:
// first-plugin.ts
import {definePlugin} from 'sanity'
export const firstPlugin = definePlugin({
name: 'first-plugin',
document: {
actions: (prev) => [MyFirstAction, ...prev]
}
})
// second-plugin.ts
export const secondPlugin = definePlugin({
name: 'second-plugin',
document: {
actions: (prev) => [MySecondAction, ...prev]
}
})
// sanity.config.ts
export default defineConfig({
plugins: [
firstPlugin(),
secondPlugin(), // These compose automatically!
]
})Each plugin receives the actions from previous plugins through the prev parameter, so they naturally compose without overwriting each other.
This is much simpler than Studio v2's parts system (which used part:@sanity/base/document-actions/resolver). In v2, you had to manually import the default resolver using the parts system:
// Studio v2 approach (deprecated)
import defaultResolve from "part:@sanity/base/document-actions"
export default function resolveDocumentActions(props) {
return [...defaultResolve(props), MyCustomAction]
}Studio v3 eliminates this complexity - you just work with the prev parameter in your resolver function, and the framework handles all the composition for you.
Check out the document actions documentation for more examples, including how to conditionally show actions, extend built-in actions, and create actions with custom dialogs.
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store