Function handler reference
Reference documentation for the shape of the function wrapper.
Every Function must export a handler. Handlers contain the logic that the Function infrastructure runs when your function is invoked.
Create a function handler with the sanity functions add command. Every handler receives an object containing context and event parameters. The function does not require a return value.
context properties
clientOptions
object
Provides properties for configuring the Sanity client (
@sanity/client). Most commonly used to pass details about the invoking project dataset to a client configuration. See the configuring@sanity/clientin Functions guide for details.local
boolean
The
context.localvalue is set totruefor functions invoked withsanity functions testandsanity functions dev. This can be helpful when you want code to only execute in local environments.It is
undefinedfor functions in production.eventResourceType
string
The resource type that triggered the function. For Document functions, this would be
dataset. For Media Library functions, this would bemedia-library.eventResourceId
string
The resource ID that triggered the function. For Document functions, this would be the ID of a dataset in the form
<project-id>.<dataset-name>. For Media Library functions, this would be the Media Library ID.resources
object
An API for looking up other resources declared in the same Blueprint: datasets, functions, CORS origins, projects, roles, and webhooks by name, without hardcoding their IDs.
clientOptions properties
projectId
string
The ID of the project that triggered this function.
dataset
string
The dataset name of the project that triggered this function.
The
sanity functions testcommand won't include a dataset by default. Run with the--datasetflag to pass a dataset toclientOptions. For example:sanity functions test log-event --dataset productionapiHost
string
Defaults to
https://api.sanity.io.token
string
A token with access to your Sanity project. It is recommended to define a Robot Token Blueprint resource yourself with explicit permissions and assign the token to your Function resource. For
sanity.function.documentFunctions, this token is automatically generated with theeditorrole and added to your project when deploying the blueprint. For other function types, you must explicitly define a Robot Token resource. See Using robot tokens with Functions for more details.The
sanity functions testcommand won't include a token by default. Run with the--with-user-tokenflag to pass the logged-in user's token.Note: the token is obfuscated in logs for security. You can directly use it to configure the Sanity client or to make API calls.
Example clientOptions
{
clientOptions: {
apiHost: 'https://api.sanity.io',
projectId: 'abc123',
dataset: 'production',
token: '***************'
}
}resources properties
context.resources gives your function access to the other resources declared in its Blueprint, so you can reference them by name instead of hardcoding IDs that can change between deployments or environments.
It's a callable object rather than a plain record, and supports a few different ways of looking things up:
Look up any resource by name
const resource = context.resources('my-cors-origin')Searches across all resource types and returns the first resource with a matching name, or undefined if none exists.
Look up a resource by type and name
const ds = context.resources.dataset('my-dataset')
const fn = context.resources.function('my-other-function')
const cors = context.resources.cors('my-cors-origin')
const project = context.resources.project('my-project')
const role = context.resources.role('my-role')
const webhook = context.resources.webhook('my-webhook')Each of these narrows the lookup to a single resource type and returns undefined if no resource of that type has that name.
Get every resource
const all = context.resources.all()
Returns a flat array of every resource in the Blueprint, regardless of type.
Iterate over every resource
for (const resource of context.resources) {
console.log(resource.name, resource.type)
}context.resources is iterable, so you can loop over every resource directly without calling .all() first.
The BlueprintResource shape
Every lookup, whether by name, by type, or through .all() / iteration, returns objects (or undefined) with this shape:
interface BlueprintResource<TType extends string = string> {
id: string
name: string
type: TType
}Example context.resources
import { documentEventHandler } from '@sanity/functions'
export const handler = documentEventHandler(async ({ context }) => {
const notificationsDataset = context.resources.dataset('notifications')
if (!notificationsDataset) {
console.log('No "notifications" dataset resource found in this Blueprint')
return
}
console.log('Found dataset resource:', notificationsDataset.id)
})event properties
Contains the shape of the event, which depends on the event:
- In the case of
documentandmedia-libraryFunction events, likepublish, the event shape is the document. This will vary based on your schema. - In the case of
sync-tag-invalidateFunction events, the sync tags will be present underevent.data.syncTags.
Example document event
{
data: {
_id: '1234',
_type: 'article',
title: 'Functions quick start',
_createdAt: '2025-04-24T16:26:58.901Z',
_publishedAt: '2025-04-24T16:26:58.901Z',
}
}Example sync-tag-invalidate event
{
data: {
syncTags: ['s1:1023', 's3:3021']
}
}Example handler
import { documentEventHandler } from '@sanity/functions'
export const handler = documentEventHandler(async ({ context, event }) => {
console.log("Context: ", context)
console.log("Event: ", event)
})export async function handler({context, event}) {
console.log("Context: ", context)
console.log("Event: ", event)
}Type support
When you create a new TypeScript function with sanity functions add, you'll be prompted to add types.
If you did not add types as part of the init process, they are available in the @sanity/functions package:
npm install @sanity/functionspnpm add @sanity/functionsyarn add @sanity/functionsbun add @sanity/functionsYou can then import and use the documentEventHandler helper to provide type support. See the "Example handler" section for implementation details.
Basic usage
Import documentEventHandler.
import {documentEventHandler} from '@sanity/functions'
export const handler = documentEventHandler(async ({context, event}) => {
// Your function implementation
console.log('Document updated:', event.data)
})Pass type for event data
If you need to type event.data, and you know the shape of your incoming data, you can provide it to documentEventHandler.
import {documentEventHandler} from '@sanity/functions'
interface NotificationData {
documentId: string
text: string
}
export const handler = documentEventHandler<NotificationData>(async ({event}) => {
console.log(event.data.text) // Typed as `string`
console.log(event.data.notSet) // Will yield type error
})Type only (TypeScript)
Import the DocumentEventHandler type.
import {type DocumentEventHandler} from '@sanity/functions'
export const handler: DocumentEventHandler = async ({context, event}) => {
// …
}
// …you can also define the data type:
export const handler: DocumentEventHandler<{text: string}> = async ({event}) => {
console.log(event.data.text)
}Type only (JavaScript)
Use the @type comment syntax.
/** @type {import('@sanity/functions').DocumentEventHandler} */
export const handler = async ({context, event}) => {
console.log(event.data.text)
}
// …you can also define the data type:
/** @type {import('@sanity/functions').DocumentEventHandler<{text: string}>} */
export const handler = async ({event}) => {
console.log(event.data.text)
}