Create a Scheduled Function
Create your first scheduled function, a Sanity function that runs on a set schedule, with Blueprints.
Functions allow you to run small, single-purpose code whenever your content in Sanity changes. This guide explains how to set up your project, initialize your first blueprint, add a function, and deploy it to Sanity's infrastructure.
Prerequisites:
- The latest version of
sanityCLI (sanity@latest) is recommended to interact with Blueprints and Functions as shown in this guide. You can always run the latest CLI commands withnpx sanity@latest. - Node.js v24.x. We highly suggest working on this version as it is the same version that your functions will run when deployed to Sanity.
- Different plans offer different function cadence limits. Check the Functions pricing section for more details.
- If you’re using an existing blueprint, it needs to use an organization-scoped stack.
- Deploying an organization-scoped stack requires the organization admin role, the new blueprint deployer role, or a robot token with the
sanity.blueprints.deploypermission.
If you’ve previously set up your project and added functions, skip ahead to the Add a scheduled function section.
Set up your project
To create a function, you need to initialize a blueprint. Blueprints are templates that describe Sanity resources. In this case, a blueprint describes when your function will run. We recommend keeping functions and blueprints a level above your Studio directory.
For example, if you have a Marketing Website that uses Sanity, you may have a structure like this:
marketing-site/
├─ studio/
├─ next-app/If you initialize the blueprint in the marketing-site directory, functions and future resources will live alongside the studio and next-app directory.
Functions and Blueprints match your workflow
While the example is our preferred way to organize Blueprints, Functions, and Sanity projects, you can initialize your first blueprint wherever you like. You can even store them inside your Studio directory.
Create a blueprint
Initialize your first blueprint with the init command. Replace <organization-id> with your organization ID, found in manage.
npx sanity@latest blueprints init . --type ts --stack-name production --organization-id <organization-id>
pnpm dlx sanity@latest blueprints init . --type ts --stack-name production --organization-id <organization-id>
yarn dlx sanity@latest blueprints init . --type ts --stack-name production --organization-id <organization-id>
bunx sanity@latest blueprints init . --type ts --stack-name production --organization-id <organization-id>
This configures an organization-scoped blueprint stack, adds a sanity.blueprint.ts config file to the current directory (.), and creates a new stack named production.
Follow the prompt and run your package manager’s install command to add the dependencies.
npm installpnpm installyarn installbun installAdd a scheduled function
Use the sanity functions add command to add a new function. You can also run it without any flags for interactive mode.
npx sanity@latest functions add --name expire-cache --type scheduled-function --language ts --installer npm
pnpm dlx sanity@latest functions add --name expire-cache --type scheduled-function --language ts --installer npm
yarn dlx sanity@latest functions add --name expire-cache --type scheduled-function --language ts --installer npm
bunx sanity@latest functions add --name expire-cache --type scheduled-function --language ts --installer npm
If you’re using a package manager other than npm, set the --installer flag to your package manager, like pnpm or yarn. Run sanity functions add --help for more details.
After running the command, follow the prompt and add the function declaration to your sanity.blueprint.ts configuration. Your file should look like this:
import {defineBlueprint, defineScheduledFunction} from '@sanity/blueprints'
export default defineBlueprint({
resources: [
defineScheduledFunction({name: 'expire-cache', event: {expression: '0 0 * * *'}}),
],
})This is the minimal configuration for defining a function in a blueprint file. You can see all available options in the Function section of the Blueprints configuration reference documentation.
If you've followed the directory structure mentioned earlier, you'll see it grow to something like this:
marketing-site/ ├─ studio/ ├─ next-app/ ├─ sanity.blueprint.ts ├─ package.json ├─ node_modules/ ├─ functions/ │ ├─ expire-cache/ │ │ ├─ index.ts
After updating the sanity.blueprint.ts file, open functions/expire-cache/index.ts in your editor.
The scheduledEventHandler function
TypeScript functions can take advantage of the scheduledEventHandler helper function to provide type support. Examples in this article include both TypeScript and JavaScript function syntax.
Every function exports a handler from the index file.
import { scheduledEventHandler } from '@sanity/functions'
export const handler = scheduledEventHandler(async ({ context }) => {
const time = new Date().toLocaleTimeString()
console.log(`👋 Your Sanity Function was called at ${time}`)
})export async function handler({context}) {
const time = new Date().toLocaleTimeString()
console.log(`👋 Your Sanity Function was called at ${time}`)
}Use the Sanity Client
If you plan to interact with a Sanity project’s dataset from your scheduled function, you can install the Sanity client and configure it. As scheduled functions are organization-scoped, they don’t have a project and dataset in their context. You need to explicitly define a robot token and set the projectId and dataset when configuring the client.
Create the robot token in your blueprint and reference it from the scheduled function definer:
import { defineBlueprint, defineScheduledFunction, defineRobotToken } from '@sanity/blueprints'
export default defineBlueprint({
resources: [
defineRobotToken({
name: 'my-robot',
label: 'My Robot',
memberships: [
{
resourceType: 'project',
resourceId: 'abc123',
roleNames: ['editor'],
},
],
}),
defineScheduledFunction({
name: 'expire-cache',
event: {expression: '0 0 * * *'},
robotToken: '$.resources.my-robot.token',
}),
],
})Configure the client:
import { scheduledEventHandler } from '@sanity/functions'
import { createClient } from '@sanity/client'
export const handler = scheduledEventHandler(async ({ context }) => {
const time = new Date().toLocaleTimeString()
console.log(`👋 Your Sanity Function was called at ${time}`)
const client = createClient({
projectId: '<your-project-id>',
dataset: '<your-dataset>',
apiVersion: '2026-04-29',
token: context.clientOptions?.token,
})
})Set a schedule
Scheduled function events can use the universal, but often difficult to read, UNIX Cron Expression format. To make it easier to understand when your function will run we also support an explicit event format.
import {defineBlueprint, defineScheduledFunction} from '@sanity/blueprints'
export default defineBlueprint({
resources: [
defineScheduledFunction({
name: 'expire-cache',
event: {
minute: '0',
hour: '0',
dayOfWeek: '*',
month: '*',
dayOfMonth: '*',
}
}),
],
})import {defineBlueprint, defineScheduledFunction} from '@sanity/blueprints'
export default defineBlueprint({
resources: [
defineScheduledFunction({
name: 'expire-cache',
event: {
expression: '0 0 * * *',
}
}),
],
})While this format is more verbose, it is easier to read that this function will run at midnight UTC every day of the year.
Set a timezone (optional)
In order to give you better control over exactly when you function executes you can provide a timezone property to your schedule function.
import {defineBlueprint, defineScheduledFunction} from '@sanity/blueprints'
export default defineBlueprint({
resources: [
defineScheduledFunction({
name: 'expire-cache',
event: {
minute: '0',
hour: '0',
dayOfWeek: '*',
month: '*',
dayOfMonth: '*',
},
timezone: 'America/New_York'
}),
],
})The timezone property supports an IANA time zone identifier, such as America/New_York or Europe/Berlin. If a timezone isn’t set, the schedule defaults to UTC.
Test the function locally
You can test functions locally with the functions development playground. Local testing is a great way to experiment without affecting your usage quota.
To launch the development playground, run the following:
npx sanity functions dev
pnpm dlx sanity functions dev
yarn dlx sanity functions dev
bunx sanity functions dev
If you run this on the starter function from earlier, you'll see the default output message in the console pane.
Development playground
In addition to the sanity functions dev command, there's also a more traditional CLI testing interface.
Run the sanity functions test functionName command to run the function locally. You can learn more in the local testing guide and the functions CLI reference.
Deploy the blueprint
Once you're satisfied that the function works as expected, deploy it by deploying the blueprint stack.
npx sanity blueprints deploy
pnpm dlx sanity blueprints deploy
yarn dlx sanity blueprints deploy
bunx sanity blueprints deploy
You can begin using your function when the deployment finishes. In the case of scheduled functions, you’ll need to wait for the event interval for it to run.
If you need to change the function, update your code and re-run the deploy command to push the new changes live.
Check the logs
When you tested the function locally, you saw the logs directly in your console. Once deployed, the function and its logs are in the cloud.
View the logs with the functions logs command. Replace expire-cache with your function name.
npx sanity functions logs expire-cache
pnpm dlx sanity functions logs expire-cache
yarn dlx sanity functions logs expire-cache
bunx sanity functions logs expire-cache
This command outputs the function's logs. Run the command again after the scheduled interval passes to see new logs.
Destroy a deployed blueprint
Sometimes you want to remove a deployed resource so it won't run anymore or affect any future usage quotas.
To remove a resources created with a blueprint, you need to either:
- Remove the definition from the blueprint, and run the
deploycommand again. - Destroy the blueprint with the
destroycommand.
The blueprints destroy command removes, or undeploys, the blueprint and all of its resources from Sanity's infrastructure. It does not remove your local files.
npx sanity blueprints destroy
pnpm dlx sanity blueprints destroy
yarn dlx sanity blueprints destroy
bunx sanity blueprints destroy
To remove the resource from the blueprint locally, you can remove it from the resources array in the sanity.blueprint.ts file, then delete any associated files.
Redeploying a destroyed blueprint
When you run blueprints destroy, it's as if you never used blueprints init during setup. The only difference is you still have all the files in your directory. To use this blueprint again and redeploy it, you'll need to let Sanity know about it. You can do this by running init again:
npx sanity blueprints init
pnpm dlx sanity blueprints init
yarn dlx sanity blueprints init
bunx sanity blueprints init
This launches an editing interface that lets you reconfigure the blueprint, if needed, and it reconnects the blueprint to Sanity. Now you can add more functions or redeploy. Keep in mind that any environment variables added before destroying the blueprint will not carry over.
