Testing functions locally
Simulate Functions locally with real data and an interactive playground.
Developing functions requires a different mindset than developing your studio or front-end. They react to changes in your data. To avoid making a change, deploying, changing a document, and checking the logs of a function, you can take advantage of the included local testing tools to simulate how your functions will interact with your data.
Prerequisites:
- Complete the Functions quick start, or be comfortable writing and deploying a Sanity Function.
- The latest version of the
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. The commands in this guide requiresanityv4.9.0 or later. - Run the commands in this guide from the directory containing your blueprints configuration. If you're not already logged in, the CLI prompts you to do so.
Local testing applies your function's filter and projection in the same way as a deployed function. If the data you supply doesn't match the filter, the function isn't invoked.
There are two approaches to running Sanity Functions locally. The dev command launches the development playground—a visual interface where you can run functions, edit the test data, and view the output. The test command offers a more traditional CLI experience where you can pass settings and test data directly as you invoke functions.
Development playground
The Functions CLI includes an interactive playground where you can test your functions and see results prior to deploying them to Sanity's infrastructure.
Run the following command from your blueprint directory:
npx sanity@latest functions devpnpm dlx sanity@latest functions devyarn dlx sanity@latest functions devbunx sanity@latest functions devThis starts a local server running at http://localhost:8080. You can also specify a port with the --port flag.
Parts of the playground interface
- Select which project, dataset, event type, and API version you want to use to test the function.
- Select the function you want to test.
- Toggle With Token to supply a
tokento the function handler'scontext.clientOptionsobject. A token is omitted from local testing unless this is toggled. - Optionally, pass a valid document ID and select the Fetch Document button to fetch the document and populate the sample document field with real data.
- You can edit the Document panel manually, or use the Fetch Document button (4). The input expects a document-like shape. When you select the update event, the Document panel is replaced by Before Document and After Document panels.
- Output from the function is displayed in the console. You can toggle the Preserve Log option to keep logs between runs.
- Run the function locally with the Run button.
You can stop the playground at any time by returning to your terminal and pressing Control+C.
Test functions from the CLI
If you prefer a CLI-based testing interface, you can run the following command:
npx sanity@latest functions test FUNCTION_NAMEpnpm dlx sanity@latest functions test FUNCTION_NAMEyarn dlx sanity@latest functions test FUNCTION_NAMEbunx sanity@latest functions test FUNCTION_NAMEReplace FUNCTION_NAME with the name of a function defined in your blueprint. Output from your functions logs to the console.
Common CLI flags
The CLI includes flags to help you supply data and configuration settings to your functions. The following are some common flags in use. To see a full list, see the functions CLI reference documentation or run npx sanity functions test --help.
Supply data from a document in your dataset
Use the --dataset, --project-id, and --document-id flags to fetch real documents to use as source data for your function.
npx sanity@latest functions test log-event --document-id 52df8926-1afe-413b-bd23-e9efbc32cea3 --project-id <your-project-id> --dataset productionpnpm dlx sanity@latest functions test log-event --document-id 52df8926-1afe-413b-bd23-e9efbc32cea3 --project-id <your-project-id> --dataset productionyarn dlx sanity@latest functions test log-event --document-id 52df8926-1afe-413b-bd23-e9efbc32cea3 --project-id <your-project-id> --dataset productionbunx sanity@latest functions test log-event --document-id 52df8926-1afe-413b-bd23-e9efbc32cea3 --project-id <your-project-id> --dataset productionReplace <your-project-id> with your project ID. If you omit --project-id, the CLI uses the project ID stored in your blueprint configuration.
Simulate event triggers
Sometimes you have logic in your function that reacts to different events, like delta::operation. Use the --event flag to simulate different event types. The default is create.
npx sanity@latest functions test log-event --event deletepnpm dlx sanity@latest functions test log-event --event deleteyarn dlx sanity@latest functions test log-event --event deletebunx sanity@latest functions test log-event --event deleteSupply data from a file or string
Use --file to read a JSON file, or --data to pass a JSON string. The two flags can't be used together.
npx sanity@latest functions test log-event --file sample-document.jsonnpx sanity@latest functions test log-event --data '{ "_type": "post", "_id": "123456", "content": "test content" }'Supply before and after documents for update events
When you use --event update, you must supply a before and an after document with one of these flag pairs: --document-id-before and --document-id-after, --data-before and --data-after, or --file-before and --file-after. These flags supply the changes between two documents for delta GROQ functions. Without a pair, the command exits with When using --event=update, you must provide one of the following flag pairs:.
npx sanity@latest functions test log-event --event update --document-id-before BEFORE_DOCUMENT_ID --document-id-after AFTER_DOCUMENT_ID --dataset productionpnpm dlx sanity@latest functions test log-event --event update --document-id-before BEFORE_DOCUMENT_ID --document-id-after AFTER_DOCUMENT_ID --dataset productionyarn dlx sanity@latest functions test log-event --event update --document-id-before BEFORE_DOCUMENT_ID --document-id-after AFTER_DOCUMENT_ID --dataset productionbunx sanity@latest functions test log-event --event update --document-id-before BEFORE_DOCUMENT_ID --document-id-after AFTER_DOCUMENT_ID --dataset productionReplace BEFORE_DOCUMENT_ID and AFTER_DOCUMENT_ID with the IDs of the documents to use as the before and after states. The CLI fetches each document by its exact ID, and passes the after document to your function as the payload.
Include your personal token for API calls
Local invocations don't include a token by default. By setting the flag, the function handler will have access to it at context.clientOptions.token.
npx sanity@latest functions test log-event --with-user-tokenpnpm dlx sanity@latest functions test log-event --with-user-tokenyarn dlx sanity@latest functions test log-event --with-user-tokenbunx sanity@latest functions test log-event --with-user-tokenTips and best practices
Use real data that matches your event
Your blueprint defines a function's event, including the filter and projection. The testing tools respect these settings and won't invoke a function if the incoming document shape wouldn't trigger it in a production setting.
Detect local invocation
Even when you test your functions locally, your code still executes. If you're interacting with a Sanity dataset or external API from within a function, be careful not to trigger writes accidentally.
You can avoid accidental writes by checking if a function is invoked locally. Both the test and dev commands set the context.local value to true. It remains undefined in deployed functions.
if (context.local) {
console.log('This code only runs when testing locally.')
}
if (!context.local) {
console.log('This code only runs in the deployed function.')
}You can also pair this with the dryRun functionality in many Sanity libraries and APIs. For example:
// will set dryRun to true in test / dev
client
.patch('bike-123')
.set({inStock: false})
.inc({numSold: 1})
.commit({ dryRun: context.local })// will set dryRun to true in test / dev
client.action({
actionType: 'sanity.action.document.create',
publishedId: 'bike-123',
attributes: {_id: 'drafts.bike-123', name: 'Sanity Tandem Extraordinaire', _type: 'bike', seats: 1},
ifExists: 'fail',
},
{dryRun: context.local}
)client.agent.action.generate({
schemaId: 'your-schema-id',
documentId: 'your-document-id',
instruction: 'Write a summary for the following topic: $topic',
instructionParams: {
topic: 'Grapefruit',
},
target: {path: ['body']},
noWrite: context.local
})Was this page helpful?
Feedback submitted, thanks for helping us improve the docs. Have you tried these alternatives?