Functions quick start
Start building with Functions by initializing and deploying a new function to Sanity's infrastructure.
Functions allow you to run small, single-purpose code whenever your content in Sanity changes. This guide explains how to set up your project, create your first Blueprint, initialize a Function, and deploy it to Sanity's infrastructure.
Avoid recursive loops
At this time, functions don't prevent recursive loops. Use caution when writing functions that may trigger themselves. For example, don't publish a document with the client that meets the same criteria as the document that triggered it.
If you initiate a recursive function, your organization may be rate-limited for the remainder of the month. If you think you've deployed a recursive function, immediately override the deployment with new code, or destroy
the blueprint.
Prerequisites:
sanity
CLI v3.88.1 or higher is required to interact with Blueprints and Functions. You can always run the latest CLI commands withnpx sanity@latest
.- Node.js v22.x. We highly suggest working on this version as it is the same version that your functions will run when deployed to Sanity.
- An existing project and a role with project update permissions.
Set up your project
To create your first function, you need to initialize a blueprint. Blueprints are templates that describe Sanity resources. In this case, a blueprint describes how your function will connect with your Sanity project. 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.
marketing_site/
├─ studio/
├─ next-app/
├─ functions/
│ ├─ myFunction/
│ │ ├─ index.js
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.
If you're using version control, you may also want to add the following lines to your .gitignore
file.
functions/**/.build/**
.sanity/*
Create a blueprint
Initialize your first blueprint with the init
command. It will prompt you for the following:
- Format: This guide uses JSON.
- Project: Select your project. This is the project that will trigger functions.
npx sanity@latest blueprints init
This creates a few configuration files in your project directory.
Create a function
Use the blueprints add function
command to add a new function. The CLI prompts you for the following:
- Function name: Set a name for your function. This determines the function name and the name of its directory. For this example, we'll call it "logEvent".
- Function type: Select the document action that will trigger the function. For this example, select Document Publish.
- Function language: Select your preferred language. For this example, we'll select TypeScript.
npx sanity blueprints add function
After defining the name and selecting a type, Blueprints updates the blueprints.json
config, creates a local functions
directory, a subdirectory with the function name, and some starter code.
Every function consists of a handler
exported by index.js
.
export async function handler({context, event}) {
const time = new Date().toLocaleTimeString()
console.log(`👋 Your Sanity Function was called at ${time}`)
}
The handler
receives a context
and an event
. The context contains information to help you interact with your Sanity datastore, such as clientOptions
to configure a @sanity/client
.
The event
contains information about the action that triggered the function. The most useful property is event.data
, which contains the contents of the document. You can learn more in the Function handler reference.
Limit the scope with GROQ
Right now, the function runs every time any document publishes. This includes system documents. You'll almost always want to scope your functions to specific scenarios with GROQ filters.
Open the blueprints.json
file and you should see the following:
{
"blueprintVersion": "2024-10-01",
"resources": [
{
"displayName": "logEvent",
"name": "logEvent",
"src": "functions/logEvent",
"type": "sanity.function.document",
"event": {
"on": [
"publish"
]
}
}
]
}
Add a filter
property to the event
object. Set it to match a document type that works for your project.
{
"blueprintVersion": "2024-10-01",
"resources": [
{
"displayName": "logEvent",
"name": "logEvent",
"src": "functions/logEvent",
"type": "sanity.function.document",
"event": {
"on": [
"publish"
],
"filter": "_type == 'post'"
}
}
]
}
Only include the filter contents, the portion inside the square brackets, of your GROQ query. For example, rather than *[_type == 'post']
, only include _type == 'post'
.
You can also include a projection
property in event
to shape the contents passed to the event. Like with filter, only include the inner contents of the curly brace wrapper. Projections don't limit what fields trigger the function, only which data is passed into the function.
Limited GROQ support
Unlike webhooks, you cannot use Delta GROQ in Function filters.
Test the function locally
You can test functions locally with the functions test
command. Local testing is a great way to experiment without affecting your usage quota.
To test a function without passing in any data, run the following:
npx sanity functions test logEvent
If you run this on the starter function from earlier, you'll see a response similar to the following:
Logs:
👋 Your Sanity Function was called at 11:48:21 AM
Response:
You can also pass in JSON as a file (--file
) or data string (--data
) to substitute the event
payload.
npx sanity functions test logEvent --file payload.json
npx sanity functions test myFunction --data '{ "doc": { "_id": "123456" } }'
Capture a document for easier testing
To make testing easier, it's helpful to capture the contents of an example document. You can do this from the document view in Studio by selecting "..." from the top right, selecting inspect, and then selecting Raw JSON. Copy the contents and save them to a JSON file. Now you can pass this to the function with the test
command.
If you're using the project structure from the beginning of this guide, you can navigate down into your studio
directory and run:
npx sanity@latest documents get "<document-id>" > ../payload.json
Replace with a document ID, and this will create a payload.json file in the directory above your studio. Don't forget to cd ..
back up to the parent after.
Note: You may need to wrap the edit the JSON file so that the contents match the expected event
shape of the function handler.
Update your function to log the event
and you'll see the data/file contents in the Logs part of the output the next time you run the test command.
export async function handler({context, event}) {
const time = new Date().toLocaleTimeString()
console.log(`👋 Your Sanity Function was called at ${time}`)
console.log('Event:', event)
}
Test ignores event settings
The test
command ignores filter
, projection
, and on
settings. You should pass a payload that matches the expected shape to mirror what the live event will send.
Deploy a function
Once you're satisfied that the function works as expected, you can deploy it by deploying the blueprint.
npx sanity blueprints deploy
You can begin using your function when the deployment is finished. If you set a filter earlier, edit a document that matches it and publish the changes to trigger the function.
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 logEvent
with your function name.
npx sanity functions logs logEvent
This command outputs the function's logs. Try updating your document, publishing the change, and running the command again to see new logs.
System documents
If you didn't limit the scope of the function by setting a GROQ filter earlier, every change to a published document will run the function. This can greatly increase your usage, so it's best to create specific filters for your documents.
Destroy a deployed blueprint
Sometimes you want to remove a deployed function so it won't run anymore or affect any future usage quotas. The blueprints destroy
command removes, or undeploys, the blueprint and all of its functions from Sanity's infrastructure. It does not remove your local files.
Remove the test function:
npx sanity blueprints destroy
To remove the function from the blueprint locally, you can remove it from the resources
array in the blueprints.json
file, then delete the logEvent
folder from the functions
directory.
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 the following:
npx sanity blueprints config --edit --test
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.
Was this page helpful?