Sitecore XM Cloud GraphQL: A Practical Guide to Building Efficient Content Queries
Introduction
Sitecore XM Cloud is a headless CMS. This implies that while the content is hosted on Sitecore, the presentation can be hosted anywhere, often a modern frontend such as Next.js. However, there is one question that is always raised when using headless architecture: how will the frontend obtain the required content?
In that regard, GraphQL provides the answer. Unlike traditional APIs that return a certain payload from an endpoint, GraphQL allows the frontend to ask for exactly the fields it requires.
But writing such a query is quite straightforward. Real projects grow: content structures deepen, templates multiply, items get translated, and references start pointing at other references. Queries grow with them.
Queries that grow carelessly pull back fields nobody uses, become difficult to change, and eventually break against endpoint limits on query depth.
This article covers the techniques that keep queries lean as a project scales. Rather than surveying every GraphQL feature, it focuses on what developers reach for most often when building headless Sitecore applications:
- GraphQL search queries
- _path and _templates filtering
- Language filtering
- GraphQL variables
- Multilist and reference fields
- Query optimization
- Common GraphQL errors
The examples use a tournament-based content structure, but the same principles apply to news, teams, FAQs, products, events, and any other structured Sitecore content.
Why Use GraphQL with Sitecore XM Cloud?
In a traditional API approach, an endpoint generally determines what information is returned. This can sometimes result in an application receiving more data than it actually needs.
GraphQL takes a different approach. The client defines the fields it wants in the query.
For example, a tournament listing component may only require:
- Tournament ID
- Tournament name
- Tournament logo
- Tournament status
There is little benefit in retrieving every field stored on the Tournament item if the component does not use them.
This makes GraphQL particularly useful for headless Sitecore implementations because developers can design queries around the requirements of individual frontend components.
A simplified architecture looks like this:
Sitecore XM Cloud
|
| GraphQL
v
Next.js App
|
v
React Components
Sitecore remains responsible for content management, while the frontend consumes the required content through GraphQL.
Understanding Sitecore GraphQL Search
One of the most useful capabilities when working with Sitecore content is searching for multiple items based on specific conditions.
Instead of requesting individual items one at a time, a search query can locate content based on its location, template, language, or other indexed properties.
This is particularly useful for components such as:
- Tournament lists
- Team lists
- Search results
For example, imagine a Sitecore content structure like:
Data
βββ Tournaments
β βββ Tournament A
β βββ Tournament B
β βββ Tournament C
β
βββ Teams
βββ Team A
βββ Team B
βββ Team C
If a component needs all Tournament items, it would be better to search within the Tournament folder rather than querying every tournament individually.
This is where _path becomes useful.
Example 1: Searching Content Using _path and _templates
A practical Sitecore GraphQL search query can combine _path, _templates, and a language variable.
query TournamentList($language: String!) {
search(
where: {
AND: [
{
name: "_path"
value: "{TOURNAMENT-FOLDER-ID}"
operator: CONTAINS
}
{
name: "_templates"
value: "{TOURNAMENT-TEMPLATE-ID}"
operator: CONTAINS
}
]
}
language: $language
) {
results {
items {
id
name
}
}
}
}
The corresponding variables are:
{
"language": "en"
}
Understanding the Query
There are several important concepts in this example.
_path
The _path condition defines the area of the Sitecore content tree that should be searched.
{
name: "_path"
value: "{TOURNAMENT-FOLDER-ID}"
operator: CONTAINS
}
Instead of searching the entire content tree, the query limits the search to items located beneath the specified folder.
This is useful for dynamic content because new tournament items can be created by content authors without requiring a developer to update the query.
For example:
Data
βββ Tournaments
βββ Tournament A
βββ Tournament B
βββ Tournament C
When another tournament is added below the same folder, it can be discovered by the same query.
_templates
The _templates condition identifies the type of content that should be returned.
{
name: "_templates"
value: "{TOURNAMENT-TEMPLATE-ID}"
operator: CONTAINS
}
This is particularly useful when a folder contains different types of Sitecore items.
Using _path together with _templates gives the query two levels of control:
Where should Sitecore search?
_path
and:
What type of item should Sitecore return?
_templates
Combining these conditions helps prevent unrelated content from being returned to the frontend.
Language Filtering with GraphQL Variables
Multilingual content is common in Sitecore XM Cloud implementations.
A tournament may have different language versions:
Tournament
βββ English
βββ Arabic
Instead of creating separate queries for every language, a variable can be used.
The query defines:
query TournamentList($language: String!) {
and the language is supplied separately:
{
"language": "en"
}
For Arabic content, the same query can be reused:
{
"language": "ar"
}
This approach provides a clean separation between the query itself and the values supplied to it.
It also makes the query easier to reuse from a Next.js application where the current language may be determined dynamically from the application's routing or localization configuration.
Why GraphQL Variables Matter
Variables are useful whenever a value changes between requests.
Without variables, developers may be tempted to create multiple versions of the same query with different values.
For example:
TournamentListEnglish
TournamentListArabic
TournamentListJapanese
This creates unnecessary duplication.
Instead, one query can accept a language variable:
query TournamentList($language: String!) {
...
}
The application can then provide:
{
"language": "en"
}
or:
{
"language": "ar"
}
The same principle can be applied to other dynamic values such as item IDs, search terms, paths, or pagination parameters.
Working with Multilist and Reference Fields
Sitecore content models frequently contain relationships between items.
For example, a Tournament template may contain a multilist field called Teams, allowing content authors to select multiple Team items.
The relationship can conceptually look like this:
Tournament
|
+-- Team A
+-- Team B
+-- Team C
In this situation, the frontend may need the actual referenced Team items rather than only the IDs stored in the multilist field.
GraphQL can expose the referenced items through the field's target items.
Example 2: Retrieving Referenced Items
The following example demonstrates a Tournament item with a teams reference field:
query Tournament($language: String!) {
item(
path: "/sitecore/content/FanID Platform/FanID/Data/Tournaments/Example"
language: $language
) {
... on Tournament {
name
teams {
targetItems {
id
name
}
}
}
}
}
The variables are:
{
"language": "en"
}
The important part of the query is:
teams {
targetItems {
id
name
}
}
Instead of working with a raw collection of referenced item IDs, the query requests the properties required from the referenced Team items.
This can simplify frontend development because the application receives structured content that can be directly mapped to a component.
For example, a tournament component could use the returned Team information to render a list of participating teams.
The same approach can be applied to other Sitecore relationships, such as:
- Related articles
- Categories
- Countries
- Stadiums
- Authors
- Related tournaments
The exact fields available depend on the Sitecore template and GraphQL schema used by the implementation.
Avoiding Unnecessary Reference Expansion
References are useful, but developers should be careful when expanding them.
Imagine a content relationship such as:
Tournament
β
Teams
β
Country
β
Stadium
β
Location
It can be tempting to retrieve everything through one large GraphQL query.
However, if the frontend only needs the team name and logo, retrieving the country, stadium, and location adds unnecessary complexity.
A better approach is to request only what the component needs.
For example, a tournament card may require:
- Tournament Name
- Team Name
- Team Logo
There is no reason to retrieve unrelated content simply because it is available through a reference.
This leads to one of the most important GraphQL development principles:
Request the content required by the component, not everything available in the content model.
GraphQL Query Optimization
A GraphQL query can be technically correct and still be inefficient.
When developing Sitecore XM Cloud applications, optimization should be considered from the beginning rather than after performance problems appear.
1. Limit the Search Scope
Use _path to restrict the search to the relevant section of the Sitecore content tree.
For example, if tournaments are stored under a specific folder, search within that folder instead of searching the entire content tree.
This makes the intent of the query clearer and helps avoid unrelated results.
2. Filter by Template
Use _templates when the search location can contain multiple types of content.
This allows the query to return only the content type required by the component.
The combination of:
_path + _templates
is a useful pattern for structured Sitecore content searches.
3. Request Only Required Fields
Avoid returning fields that the frontend does not use.
If a component only needs:
idnameimage
there is little reason to request dozens of additional fields.
Smaller responses are easier to process and maintain.
4. Avoid Excessive Query Depth
GraphQL makes it easy to navigate through related content, but deeply nested queries can become expensive.
For example:
Tournament
β Teams
β Country
β Stadium
β Location
If the frontend does not need all of this information, do not retrieve it.
Deep nesting can also cause the query to exceed the maximum depth supported by the GraphQL endpoint.
5. Reuse Queries with Variables
Variables make a query reusable.
Instead of creating separate queries for each language or dynamic value, create one query and pass the required value as a variable.
This reduces duplication and makes frontend integration cleaner.
Common Sitecore GraphQL Errors
Even a well-designed query can fail if it does not match the GraphQL schema or exceeds endpoint limitations.
Here are some common issues developers may encounter.
Query Is Too Nested
One possible error is:
Query is too nested to execute.
Depth is 17 levels, maximum allowed on this endpoint is 15.
This means the query has exceeded the maximum nesting depth configured for the endpoint.
This is usually caused by expanding too many nested relationships.
If the application genuinely needs information from multiple levels, consider whether the data can be retrieved through separate, smaller requests.
Cannot Query a Field
Another common error is similar to:
Cannot query field "tournaments" on type "Item".
GraphQL is strongly typed. A field may be available only on a specific type and not on the generic Item type.
When this occurs, inspect the GraphQL schema and verify the type associated with the field.
In some cases, an inline fragment may be required:
... on Tournament {
...
}
The exact type and available fields depend on the schema generated by the Sitecore implementation.
Empty Search Results
A query may execute successfully but return:
{
"items": []
}
This does not necessarily indicate a GraphQL problem.
When this happens, check:
Content Path
Verify that the _path value points to the expected Sitecore item.
Template ID
Verify that the content item is based on the template specified in _templates.
Language
Check whether the requested language version exists.
Content Availability
Verify that the content is available in the environment and context where the query is being executed.
Search Index
If the query depends on Sitecore search, verify that the expected content is available to the relevant index.
Building GraphQL Queries Based on Components
One of the best approaches to keep GraphQL queries easy to handle is to think of them in terms of frontend components.
For example, suppose a Tournament List component needs:
- Tournament Name
- Tournament Logo
- Start Date
- Status
The GraphQL query should be designed around those requirements.
A common mistake is to think:
"What data does this Sitecore item contain?"
A better question is:
"What data does this component actually need?"
This small change in thinking can prevent unnecessarily large queries.
Conclusion
GraphQL simplifies content delivery in Sitecore XM Cloud by allowing developers to retrieve only the data required by their applications. Filters like _path and _templates, language variables, and structured references make it possible to construct focused, reusable queries.
By avoiding unnecessary fields and deep nesting, developers can build GraphQL queries that are efficient, maintainable, and scalable for headless Sitecore applications.
Related Blogs
Read More
Read More
Read More