GROQ queries and security in Sanity.io
You're absolutely right to be concerned about GROQ injection! The good news is that Sanity has built-in protection through parameterized queries, which is exactly what you should be using for cases like this.
The Problem with String Interpolation
When you write something like:
const query = `*[_type == "page" && slug.current in ${slugs}]`You're doing JavaScript string interpolation, which means you're directly inserting user input into your query string. This is indeed vulnerable to GROQ injection attacks and can also cause syntax errors if the values contain special characters like quotes.
The Solution: Use GROQ Parameters
Instead, use GROQ parameters with the $ syntax:
const query = `*[_type == "page" && slug.current in $slugs]`
const params = { slugs: slugsFromUrl }
const results = await sanityClient.fetch(query, params)Parameters are passed as the second argument to client.fetch(), and the Sanity client automatically handles proper encoding and escaping.
Why Parameters Are Secure
GROQ parameters provide several critical security benefits:
Prevention of GROQ injection: Parameters must be JSON literals, so they can only contain values (not arbitrary GROQ expressions). This means user input can't alter the structure of your query.
Automatic escaping: The client library properly escapes special characters, preventing syntax errors and injection attempts.
Type safety: Parameters maintain their data types throughout the query execution.
As the Sanity documentation explains, since parameters are JSON literals, they cannot contain GROQ expressions that could alter the query structure, making them safe to pass from user input.
Best Practices
- Always use
$parametersfor dynamic values, especially anything coming from user input (URLs, form fields, etc.) - Use the Sanity JavaScript client when possible—it handles parameter encoding automatically
- If a parameter might be missing, pass
nullor use conditional logic withselect()
The GROQ parameters specification has more details on the technical implementation if you want to dive deeper into how this works under the hood.
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.