Content Lake (Datastore)

Custom GROQ functions

Learn how to create your own GROQ functions.

Sometimes you find yourself repeating the same portion of a GROQ query across multiple queries, or even within a single complex query. Custom functions for GROQ allow you to create modular, reusable sub-queries.

Prerequisites

  • An API version other than v1. Custom GROQ functions are available on every other API version, so set apiVersion explicitly on your client.
  • For generated TypeScript types, groq-js 1.24.0 or later.

Function anatomy

Custom functions look similar to other GROQ functions, but with some limitations. They require a namespace and accept exactly one parameter. Let's look at an example function that follows a reference and returns a projection that combines an author's first and last name.

All functions start with the fn keyword and contain a namespace, name, parameter, and function body. In the example above:

  • ex is the namespace.
  • name is the function name.
  • $author is the parameter.
  • $author-> { "name": firstName + " " + lastName } is the body.

Custom function declarations must happen at the start of the GROQ query and each declaration must end with a semicolon (;). You can use them anywhere you'd normally send a GROQ query, such as a Sanity client, the HTTP query API, or the Vision Tool. For example, in @sanity/client:

See the GROQ functions reference for additional details.

Supported function formats

Custom functions support a limited set of formats at this time:

  • $param{...}
  • $param->{...}
  • $param[]{...}
  • $param[]->{...}

Let's use the following documents as an example to explore each format. There is a person document, an occupation document, and two pet documents.

Basic projection

First we'll define a function that returns a basic projection. This function, ex::details, takes a $person parameter and returns a projection containing their name and age. To use the function, we pass in @ to represent the person returned by the filter.

Follow references

It's common to follow references to include part or all of their contents in the referencing object. This function follows the person's occupation reference and returns a projection with their title.

Array projection

This function iterates through the person's belongings to display their names.

Array of references

This function follows each reference in the person's pet key.

Reuse Portable Text projections

Reusing the logic for parsing Portable Text blocks is a common use case for functions. This example parses a set of blocks regardless of the incoming blocks.

Limitations

Function bodies are limited to the four formats listed under Supported function formats. Any other body is rejected with function body is not of type ast.Projection. Custom functions also do not yet support:

  • Recursion: cyclic dependency detected in function definition.
  • Accessing the parent scope: parent usage is invalid.
  • Passing more or fewer than one parameter: expected ')' following function arguments.
  • Accessing the function parameter more than once in the function body: the function argument cannot be used more than once in the function body.

TypeGen integration

TypeGen supports custom GROQ functions from groq-js 1.24.0 or later, which ships with the Sanity CLI. Use defineQuery as usual, and TypeGen generates TypeScript types that account for your function's return shape:

Reusing functions across queries

Custom functions must be declared at the start of each query. To reuse a function across multiple queries, define it as a string constant and prepend it:

Was this page helpful?