Is it Possible to Update the Sort Value via Params in a Client Query?

5 replies
Last updated: May 12, 2020
Is it possible to update the sort value eg:
 | order($sort) 
via params in a client query?
AI Update

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.

Params are only available in the query statement I believe (so between
*[…]
), not in slice, projection, order, etc. However, nothing should stop you from using a JS variable there, if that helps?
const query = groq`*[_type == $type]{...} | order("${sort}")`
ah ok thanks! Can just use JS variables. Can I ask the benefit of using
groq
?
I’m guessing variables will be important too if making pagination and updating the slice
It will work without
groq
as well I think and yep, you would probably use vars for slices too in that situation.
thanks!

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.

Was this answer helpful?