Is it Possible to Update the Sort Value via Params in a Client Query?
Unfortunately, you cannot parameterize the field name in the order() clause using something like order($sort) in GROQ. Parameters in GROQ are limited to JSON literal values (strings, numbers, booleans, arrays, objects) and cannot be used to dynamically specify field names in the order() function.
This is a known limitation of GROQ's parameter system. When you write GROQ queries with parameters, the $ syntax works great for filtering values:
*[_type == $type && status == $status]But it doesn't work for structural parts of the query like field names in order():
// ❌ This won't work
*[_type == "post"] | order($sortField)Workarounds
Since you can't parameterize the order field directly, here are the common approaches:
1. Build the query string dynamically (Most common)
Construct the entire query string in your application code before passing it to client.fetch():
const sortField = 'publishedAt'; // or from user input
const sortDirection = 'desc';
const query = `*[_type == "post"] | order(${sortField} ${sortDirection})`;
const posts = await client.fetch(query);Important: If the field name comes from user input, validate it against a whitelist to prevent injection issues:
const allowedFields = ['publishedAt', 'title', '_createdAt'];
const sortField = userInput;
if (!allowedFields.includes(sortField)) {
throw new Error('Invalid sort field');
}
const query = `*[_type == "post"] | order(${sortField} desc)`;2. Use select() with conditional logic
For a limited set of sort options, you can use GROQ's select() function to conditionally apply different orderings, though this gets unwieldy:
*[_type == "post"] | order(
select(
$sortBy == "date" => publishedAt,
$sortBy == "title" => title,
publishedAt // default
) desc
)This approach works but only lets you parameterize which field to use, not construct it dynamically from arbitrary strings. You can still pass $sortBy as a parameter to switch between predefined field options.
3. Client-side sorting
For smaller datasets, fetch all results and sort in your application code:
const posts = await client.fetch(`*[_type == "post"]`);
const sorted = posts.sort((a, b) => {
return a[sortField] > b[sortField] ? 1 : -1;
});This isn't ideal for large datasets due to performance and pagination concerns.
Why this limitation exists
GROQ parameters are designed for data values, not for structural elements of the query itself (field names, operators, functions). This is similar to SQL prepared statements where you can parameterize WHERE values but not column names or table names. It's partly a security feature and partly due to how the query parser works.
The dynamic query string approach (option 1) is what most developers use in production—just remember to validate any user input before interpolating it into your query string to avoid potential security issues.
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.