
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeLooking at your query, there are several performance issues that are likely causing slowness. Here's how to make it significantly faster:
1. String concatenation is building an invalid GROQ query
Your current approach concatenates filter conditions incorrectly. Each filter adds another array slice [condition], which doesn't create valid GROQ syntax. You need proper boolean logic with && operators.
2. No indexes are being utilized
The query starts with *[_type == "video"] which is good, but subsequent filters aren't optimized for the query engine.
3. Multiple reference dereferencing
Fields like grade[].label and category[].title suggest you're dereferencing arrays of references, which is expensive.
export async function getFilteredVideos(
limit,
filterGrade,
filterCategory,
search,
sort,
type = "Lesson Video",
subCategory
) {
console.time("videos fetch");
// Build filter conditions as an array
const conditions = ['_type == "video"', `type.name == $type`];
if (filterGrade && filterGrade !== "All Grades") {
conditions.push(`$filterGrade in grade[].label`);
}
if (filterCategory && filterCategory !== "All Categories") {
conditions.push(`$filterCategory in category[].title`);
}
if (subCategory && subCategory !== "All Subtopic") {
conditions.push(`subCategory.title match $subCategory`);
}
if (search && search !== "All") {
conditions.push(`name match $search`);
}
// Combine all conditions with &&
const filterClause = conditions.join(' && ');
// Build order clause
let orderClause = '';
if (sort === "longest") orderClause = '| order(duration desc)';
else if (sort === "shortest") orderClause = '| order(duration asc)';
else if (sort === "relevance") orderClause = '| order(type.name desc)';
// Build final query with parameters
const query = `*[${filterClause}] ${orderClause} [0...${limit}] {${videoFields}}`;
const results = await client.fetch(query, {
type,
filterGrade,
filterCategory,
subCategory,
search: search ? `${search}*` : undefined
});
console.timeEnd("videos fetch");
return results;
}1. Use query parameters: Passing values as parameters (the second argument to client.fetch()) is more secure and allows the query engine to optimize better.
2. Proper filter syntax: Combining conditions with && creates a valid GROQ filter that the query engine can process efficiently.
3. Move projection to the end: According to GROQ query optimization best practices, you should filter and sort first, then project fields. This reduces the amount of data processed.
4. Optimize array slicing: Use [0...${limit}] instead of appending the limit - this is the correct GROQ syntax for slicing.
If this is still slow with large datasets:
type.name and grade[].label (if you're on a Growth plan or higher)grade[].label and category[].title are references being dereferenced, consider denormalizing this data or using a more efficient data structurevideoFields that you actually needThe query parameter approach combined with proper filter syntax should give you a significant performance boost immediately.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store