Published on April 7, 2025
If you're reading this, you've probably used GraphQL to retrieve data for a front end. You will be familiar with the performance benefits of GraphQL and possibly even with Contentful's implementation of it.
This post will show you how to use GraphQL query filtering to squeeze more speed and efficiency out of your GraphQL back end.
Filters in GraphQL allow you to take a query that requests data for a particular data type and tell the back end how to pinpoint specific items within that dataset, so that only those are returned.
You can do this in many ways and at all levels, but the key point is that whenever you want to improve the performance of your query and reduce the data load, applying a filter is the way to do it.
In this article, we will explain GraphQL filtering using the example of a CMS that manages a blog site. Most modern CMSes use a content model to define different types of content, their structure, and how they relate to each other. In this example, we use three different content model items:
Blog Posts:
standard blog post content.
Topics
:
Attached to a blog post, these represent real world things, like products, to help categorize your content.
Tags
:
Granular metadata on posts for targeted filtering, which can also be used for internal-only categorization.
You can create all of these in the Contentful Editor and query them using the Contentful GraphiQL tool (an interactive GraphQL API explorer — one of many).
Each GraphQL implementation provides different ways to filter content. The principal method is by using any data type defined in the schema with the suffix Filter. For example, the Contentful data type BlogPost can be filtered using the BlogPostFilter data type. Because GraphQL is self-documenting, you can find this on almost every GraphQL explorer by opening the docs and searching for “filter.”
Let’s look at the different filter options …
This is one of the simplest filters you can apply and it’s mostly done on collections. If you have a BlogPost
type in your content model, there will be a BlogPostFilter
type.
So, if you have a basic query to retrieve the titles of blog posts:
You'll see something like this:
In the docs, you can check the BlogPostFilter
type and see that it provides the field title_contains
. Because this field is in a filter data type, you can use it in a where clause within the parameters of the BlogPostCollection
call:
Like so:
Any field you see in a filter data type can be used this way, making a simple but powerful mechanism to retrieve subsets of data.
Range filters allow you to filter data within a particular range. They can be used on dates, times, or numerical data. Common range filters include greater than (gt)
, greater than or equal to (gte)
, less than (lt)
, and less than or equal to (lte)
. So, if you see a filter type with a field like size_gte
you know it supports comparing the size
of the filtered type with operations like greater than or equal to
.
In Contentful, an example of a numerical field is the file size of particular assets. An asset is the part of your content model that represents media files like images and videos. You can use this field to understand how range filtering works. Start by retrieving all your assets and then use range filtering to return only the smallest items. To retrieve all your assets (warning: don’t do this for a large dataset!), run this query:
This returns (potentially) rather a lot:
But if you only want the smaller file size items, you can use size_lte
to ignore everything above 1 MB:
In this case, this returns just the smallest asset:
Nested filters includes any filter that contains another filter. For example, you could have a where
clause filtering the returned Blog Posts
by title
and then ensure that the list of Topics
attached to each Blog Post
is limited to just those containing the string “graph” (this is case insensitive).
The response contains only Blog Posts
with the string “Paginating” in the title and each of those contains only Topics that have the string “graph” in their name:
This simple example demonstrates that if you have a deep data structure you can retrieve only those elements of it that you’re interested in — especially useful when some objects in the schema might get complex or heavy. This helps reduce the amount of data returned from the query, lightening the load on your network traffic and reducing the overhead and post-processing that your front end will need to do.
Directives instruct the back end to apply rules to elements returned by the query to include or exclude particular fields. For example, you might only want the titles of blog posts for showing in a list of articles, or you might want their full content. Like in a regular function, you can use variables so you can call the same query with different values and get different results.
Here is a query using the @include()
directive to conditionally retrieve the full content of blog posts or just their titles:
If you call this query with includeContent
set to false
it will switch the main content of the blog posts off:
And here is the same query returning more content if you call it with includeContent
set to true
:
You can find out which directives are available in the schema with a GraphQL query — a very powerful function of GraphQL that effectively makes GraphQL self-documenting:
Returns the following:
You will find directives with many arguments in the Docs of your GraphQL query tool.
While not strictly filtering, you can apply paging to your results by using collection data type fields like skip
and limit
, which will skip over a number of results and restrict the size of the result set, respectively. Taking the first query above, you can reduce the initial three results down to just one by adding skip
and limit
parameters to the blogPostCollection
query:
And then you should see something like:
This is a simple example, but with different filter types containing other parameter names, you will have many options to tailor your queries and refine their results for straightforward performance improvements.
The benefit of filters is to narrow the dataset at the server level, reducing the effort and over-fetching at the back end. This improves the specificity of cached requests (especially when used with pagination), reduces database load, and ensures the client receives only the data they need.
As mentioned above, the less work the front end needs to do presenting data to the user, the better. Retrieving only the data the client actually needs makes the front end a faster and more efficient interface.
Shifting things like pagination to the server side helps optimize the client logic even further and GraphQL filtering makes this very easy.
It also reduces the amount of data sent over the wire to the client, which is beneficial for mobile or slow network connections or where data costs money.
And, of course, the more reusable a query is, the more focus it will receive during maintenance. Keeping the number of queries manageable helps prevent them from becoming increasingly complex as your schema evolves.
Use GraphQL filters where you can to ensure the performance of your queries and keep frontend responsiveness at its peak, while avoiding unnecessary maintenance.
Don’t over-filter. Be concise with the filters you use and don’t filter on fields that are irrelevant to the result of the query. This actually puts extra load on the server side and will reduce response times, much like unnecessary SQL joins put extra load on relational databases.
Ensure that nested filters are used wisely and will not conflict with the parent filters. Don’t use nested filters to remove data which is better removed by filters at a higher level and definitely don’t try to filter the same data using two filters at different levels of nesting. Like with SQL, over-joining will only slow you down.
Finally, use variables and pagination, which will help with caching and enable your GraphQL filters to perform even better. This will help network requests to be handled earlier than the database layer and can dramatically improve performance.
Contentful provides a full-featured GraphQL API with documentation with the features above, like nested filtering, that will help you get started making powerful, performant queries to bring your content to your customers fast. Sign up today to get started.
Subscribe for updates
Build better digital experiences with Contentful updates direct to your inbox.