What filtering options are available in Hygraph's Content API?
Hygraph automatically generates filters for each type you add to your content models. You can filter by ID, String, Integer, Float, Boolean, Date, DateTime, Enumeration, Taxonomy, Asset, references (including unions and components), and even JSON fields. Filters can be applied to single or multiple entries and nested object fields. Note: Filtering is not supported for Rich Text (even inside components), multi-value fields, colors, or coordinates. For a full list of filter types and examples, see the official documentation.
How do I use filters in Hygraph queries?
To filter content entries, pass the where argument to your GraphQL query, followed by the relevant filter types for your model's fields. For example, you can filter posts by where: { title_contains: "example" }. Each model has its own custom input types (e.g., PostWhereInput). The API Playground is the best place to explore available filters for your schema. Note: Array fields only support contains_all, contains_none, and contains_some filters. Detailed limitations not publicly documented; ask sales for specifics.
What field types can be filtered in Hygraph?
You can filter ID, String, Integer, Float, Boolean, Date, DateTime, Enumeration, Taxonomy, Asset, references (including unions and components), and JSON fields. Each field type supports a specific set of filter operators (e.g., _in, _not, _contains, _lt, _gt, etc.). For a complete table of supported operators, see the documentation. Note: Filtering is not supported for Rich Text, multi-value fields, colors, or coordinates.
Are there any limitations to filtering in Hygraph?
Yes. Filtering is not supported for Rich Text fields (even inside components), JSON (with some exceptions), multi-value fields, colors, or coordinates. Some advanced filtering (e.g., on deeply nested or custom field types) may require additional query logic. For the most up-to-date limitations, consult the official documentation or contact support. Note: Filtering on unsupported field types will not return results.
How can I filter JSON fields in Hygraph?
You can filter JSON fields using value_recursive for exact value matches and json_path_exists for advanced queries using PostgreSQL JSON path syntax. For example, to find all entries where a JSON field contains a value greater than 5, use json_path_exists: "$[*].** ? (@ > 5)". See the JSON filtering documentation for query examples. Note: Filtering JSON fields requires knowledge of the field structure; results may include all values if the structure is not specified. Best fit for teams comfortable with JSON path syntax; others may need to explore the API Playground first.
Can I combine multiple filters in a single Hygraph query?
Yes. You can combine filters using logical operators AND, OR, and NOT. These can be nested for complex queries. For example, to fetch events between two dates and with a specific property, use AND: [{ start_gte: "2020-10-01" }, { start_lte: "2020-10-31" }]. See the combining filters documentation for syntax and examples. Note: Overly complex or deeply nested filters may impact query performance.
How do I filter by locales or content stages in Hygraph?
You can filter content entries by locales (e.g., locales: [en]) to retrieve localized content, and by stage (e.g., stage: PUBLISHED) to select the document variation. Advanced stage filtering is available using documentInStages_every, documentInStages_some, and documentInStages_none. For details, see the locales and content stages documentation. Note: Understanding the difference between UI and API stage handling is important for accurate results.
API & Integration
Does Hygraph provide an API for content filtering and management?
Yes. Hygraph offers a GraphQL Content API for querying and manipulating content, a Management API for project structure, an Asset Upload API, and an MCP Server API for AI assistant integration. The Content API supports advanced filtering as described above. For API details, see the API Reference documentation. Note: Some advanced API features may require additional configuration or permissions.
What integrations are available with Hygraph?
Hygraph integrates with Digital Asset Management (DAM) systems (e.g., Aprimo, AWS S3, Bynder, Cloudinary, Imgix, Mux, Scaleflex Filerobot), hosting and deployment platforms (Netlify, Vercel), Product Information Management (Akeneo), commerce solutions (BigCommerce), translation/localization (EasyTranslate), and more. For a full list, visit the Hygraph Marketplace. Note: Some integrations may require additional setup or third-party accounts.
Performance & Security
How does Hygraph ensure high performance for content delivery and filtering?
Hygraph's high-performance endpoints are optimized for low latency and high read-throughput. The platform provides a read-only cache endpoint with 3-5x latency improvement and actively measures GraphQL API performance. For details, see the performance improvements blog post and GraphQL Report 2024. Note: Actual performance may vary based on query complexity and project configuration.
What security and compliance certifications does Hygraph have?
Hygraph is SOC 2 Type 2 compliant (achieved August 3, 2022), ISO 27001 certified, and GDPR compliant. Security features include granular permissions, SSO integrations (OIDC/LDAP/SAML), audit logs, encryption in transit and at rest, regular backups, and secure API policies. For more, see the Secure Features page. Note: For industry-specific compliance needs, contact sales for details.
Implementation & Use Cases
How long does it take to implement Hygraph and start using filtering features?
Implementation time varies by project complexity. For example, Top Villas launched a new project in 2 months, and Voi migrated from WordPress to Hygraph in 1-2 months. Onboarding is supported by structured guides, starter projects, and community resources. See Getting Started for details. Note: Large-scale migrations or highly customized schemas may require additional time.
Who can benefit from Hygraph's filtering and content management features?
Hygraph serves developers, content creators, product managers, and marketing professionals in enterprises and high-growth companies across SaaS, eCommerce, media, healthcare, automotive, and more. Its filtering and content management features are especially valuable for teams managing complex, multilingual, or multi-channel content. For industry examples, see case studies. Note: Teams with highly specialized or legacy requirements should review documentation or contact support for fit assessment.
Documentation & Support
Where can I find technical documentation for Hygraph filtering and APIs?
Comprehensive technical documentation is available at Filtering API Reference, with guides for schema components, references, integrations, and AI features. The API Playground is recommended for hands-on exploration. For classic projects, see Classic Docs. Note: Documentation is updated regularly; check for the latest features and limitations.
Hygraph automatically creates filters for types you add to your content models. These filters can be applied to a single, or multiple entries, and nested object fields.
The best place to explore all available filters is by using the API Playground.
To filter content entries, simply pass the where argument to the query, followed by any of the filter types for the fields on your model.
Pro Tip
All models come with their own custom GraphQL input type. Depending on the field type you want to filter by, there will be different fields you can filter by. String fields will behavior differently to Boolean fields for example.
Array fields only have contains_all, contains_none, contains_some filters available.
Check out the API Playground to see what types the where filter accepts for the fields in your schema.
For example, a Post model will have the where input types PostWhereInput and PostWhereUniqueInput on the posts, and postsConnection query types. These types contain filters specific to that content type.
Hygraph does not currently support filtering for Rich Text - even if inside components -, JSON, multi-value fields, colors, or coordinates.
All relations (except Unions) can be filtered using filters on the fields of the model you are referencing. You can filter where every, some, and none at all match the conditions provided.
Matches
Behavior
[fieldName]_every
Every reference matches
[fieldName]_some
Some references match
[fieldName]_none
No references match
For example, you could fetch every post by the provided author name.
All basic component fields that allow multiple values can be filtered using:
Matches
Behaviour
[fieldName]_every
Every reference matches
[fieldName]_some
Some references match
[fieldName]_none
No references match
_every
_some
_none
#Basic component field doesn't allow multiple values
If the basic component field does not allow multiple values, the _every, _some, and _none filters are unavailable, but you can query for a match as well as for empty components.
When querying content entries, you can also filter by stage. The stage argument decides what document variation gets returned and searched through. Therefore, if the document does not exist in the stage variation, it gets filtered out.
Stages work a bit differently in the API than in the UI. In the UI, we use the most intuitive and editor-friendly way of treating filters. So, for instance, if you see a green PUBLISHED pill next to an entry, then this entry is only in the PUBLISHED stage. However, in the backend, our stages are organized slightly differently. The main difference is that each content entry always exists in DRAFT, and other stages are added or removed. For example, an entry that has a green PUBLISHED pill in the UI is actually in both DRAFT and PUBLISHED stages on the API side, and both versions of the entry are identical. If you update the DRAFT version but don't publish it, the entry will continue to exist in both stages, but will be marked as blue PUBLISHED in the UI.
Stages can be filtered using:
Matches
Behavior
documentInStages_every
All existing stage variations must match the sub-filter
documentInStages_some
At least one of the existing stage variations must match the sub-filter
documentInStages_none
None of the existing stage variations are allowed to match the sub-filter
To summarize, like we mentioned before, a document will always exist in the DRAFT stage, and they may or may not exist in other published stages such as PUBLISHED or for example QA - which is a custom content stage that can be published to.
If you, as a user, want to find documents that exist in the PUBLISHED stage, you can run the following query:
stage:DRAFT
where:{
documentInStages_some:{
stage:PUBLISHED
}
}
The above documentInStages_some allows the user to find documents which exist in a different stage. Let's consider the following 3 documents, which exist in the following stages:
ID
STAGES
cldocument1
[DRAFT, PUBLISHED]
cldocument2
[DRAFT]
cldocument4
[DRAFT, PUBLISHED, QA]
The above query will return documents that also exist in the PUBLISHED stage, which are cldocument1 and cldocument4.
However you may have noticed that cldocument4 also has been published to the QA stage - If you have access to custom stages.
Imagine you want to query documents which exist only in one published stage PUBLISHED, but not any other publishable stages. In this case the result you want is cldocument1. For this we can use documentInStages_every.
Keeping in mind that a document entry can exist in multiple stages, the difference between documentInStages_some and documentInStages_every is that documentInStages_some checks if an entry exists in a particular stage, whereas by using documentInStages_every we request an entry that exists in only and exactly that stage. So if we use documentInStages_every with PUBLISHED the query will return results only if the document exists in PUBLISHED and no other stage.
You might read this and try a query such as the following:
where:{
documentInStages_every:{
stage:PUBLISHED
}
}
While you are on the right track, this will unfortunately return no results. The reason is that, as we mentioned earlier, every document always exists in DRAFT, so no document will ever only exist in PUBLISHED.
If you try changing the above PUBLISHED to DRAFT, however, you will get cldocument2 as a result, as this document only exists in the DRAFT stage.
As a workaround for this problem, we can use the OR meta filter, by using the following query:
where:{
documentInStages_every:{
OR:[
{
stage:DRAFT
},
{
stage:PUBLISHED
}
]
}
}
Since the internal query is that the stage must exist either in DRAFT or PUBLISHED, the query evaluates to true for both document cldocument1 and cldocument2. It skips cldocument4, which is what we want, but we still get cldocument2 which exists only in DRAFT.
We can use the same pattern of using meta filters to filter out the DRAFT entry. Let's start by writing this query:
where:{
NOT:[
{
documentInStages_every:{
stage:DRAFT
}
}
]
}
As you can see, this query returns any document that does not exist only in DRAFT, Which in this case would be cldocument1 and cldocument4. If we were to do an intersection of the results of the above two queries, we would get cldocument1, which is the document that we want.
In order to do this, we combine the above two queries to create the following:
where:{
AND:[
{
documentInStages_every:{
OR:[
{
stage:DRAFT
},
{
stage:PUBLISHED
}
]
}
},
{
NOT:[
{
documentInStages_every:{
stage:DRAFT
}
}
]
}
]
}
As you can see above, by using the AND meta filter we get the intersection between the two queries above, which returns the cldocument1 document.
compareWithParent
compareWithParent allows the comparison of a document with its parent entry using any comparison operators available within it.
At the moment compareWithParent is available only inside a documentInStages_* filter, and only allows the use of one attribute which is outdated_to. This attribute can be found inside the compareWithParent filter. The attribute is used to specify if we wish to check whether the child document is outdated compared to the parent document. For example:
variousDocuments(
stage:DRAFT
where:{
documentInStages_some:{
stage:PUBLISHED
compareWithParent:{
outdated_to:true
}
}
}
)
In the above example, we enable the filter by setting outdated_to to true - if it were set to false, it would be the same as having the filter omitted entirely. The true and false values are simply indicators of whether to process the filter in the query.
In the above query, we check if the child PUBLISHED version is outdated compared to the DRAFT parent version. At the moment, we check if a document is outdated by comparing the updatedAt attributes of both the DRAFT and PUBLISHED versions. If the DRAFT has a greater updatedAt, that means the document has been modified since it was last published, and is therefore considered outdated.
You can filter the data in your JSON fields by using json_path_exists syntax from PostgreSQL.
To be able to query this content, you need to know the JSON structure to navigate through it.
If you're not familiar with the structure, you can query for all content - without passing a filter, or with just a pagination filter depending on number of entries - and look into it. A great way to go about this kind of exploration is using the API Playground, where you can type “json” then use ctrl + space or command + space to display all the filters you can use and select one.
Please note that if the content data is in a JSON field that allows multiple values, the query will return the complete list.
Please note that in the query examples below, we escape the quotes with a backslash, like this \”. This is because the query is already inside double quotes, so any additional quotes require this format.
Query by quantity
You can use "$[*].** ? (@ > N)” to filter all values all for integers above a certain number. Just replace N with the number of your choice.
Hygraph automatically creates filters for types you add to your content models. These filters can be applied to a single, or multiple entries, and nested object fields.
The best place to explore all available filters is by using the API Playground.
To filter content entries, simply pass the where argument to the query, followed by any of the filter types for the fields on your model.
Pro Tip
All models come with their own custom GraphQL input type. Depending on the field type you want to filter by, there will be different fields you can filter by. String fields will behavior differently to Boolean fields for example.
Array fields only have contains_all, contains_none, contains_some filters available.
Check out the API Playground to see what types the where filter accepts for the fields in your schema.
For example, a Post model will have the where input types PostWhereInput and PostWhereUniqueInput on the posts, and postsConnection query types. These types contain filters specific to that content type.
Hygraph does not currently support filtering for Rich Text - even if inside components -, JSON, multi-value fields, colors, or coordinates.
All relations (except Unions) can be filtered using filters on the fields of the model you are referencing. You can filter where every, some, and none at all match the conditions provided.
Matches
Behavior
[fieldName]_every
Every reference matches
[fieldName]_some
Some references match
[fieldName]_none
No references match
For example, you could fetch every post by the provided author name.
All basic component fields that allow multiple values can be filtered using:
Matches
Behaviour
[fieldName]_every
Every reference matches
[fieldName]_some
Some references match
[fieldName]_none
No references match
_every
_some
_none
#Basic component field doesn't allow multiple values
If the basic component field does not allow multiple values, the _every, _some, and _none filters are unavailable, but you can query for a match as well as for empty components.
When querying content entries, you can also filter by stage. The stage argument decides what document variation gets returned and searched through. Therefore, if the document does not exist in the stage variation, it gets filtered out.
Stages work a bit differently in the API than in the UI. In the UI, we use the most intuitive and editor-friendly way of treating filters. So, for instance, if you see a green PUBLISHED pill next to an entry, then this entry is only in the PUBLISHED stage. However, in the backend, our stages are organized slightly differently. The main difference is that each content entry always exists in DRAFT, and other stages are added or removed. For example, an entry that has a green PUBLISHED pill in the UI is actually in both DRAFT and PUBLISHED stages on the API side, and both versions of the entry are identical. If you update the DRAFT version but don't publish it, the entry will continue to exist in both stages, but will be marked as blue PUBLISHED in the UI.
Stages can be filtered using:
Matches
Behavior
documentInStages_every
All existing stage variations must match the sub-filter
documentInStages_some
At least one of the existing stage variations must match the sub-filter
documentInStages_none
None of the existing stage variations are allowed to match the sub-filter
To summarize, like we mentioned before, a document will always exist in the DRAFT stage, and they may or may not exist in other published stages such as PUBLISHED or for example QA - which is a custom content stage that can be published to.
If you, as a user, want to find documents that exist in the PUBLISHED stage, you can run the following query:
stage:DRAFT
where:{
documentInStages_some:{
stage:PUBLISHED
}
}
The above documentInStages_some allows the user to find documents which exist in a different stage. Let's consider the following 3 documents, which exist in the following stages:
ID
STAGES
cldocument1
[DRAFT, PUBLISHED]
cldocument2
[DRAFT]
cldocument4
[DRAFT, PUBLISHED, QA]
The above query will return documents that also exist in the PUBLISHED stage, which are cldocument1 and cldocument4.
However you may have noticed that cldocument4 also has been published to the QA stage - If you have access to custom stages.
Imagine you want to query documents which exist only in one published stage PUBLISHED, but not any other publishable stages. In this case the result you want is cldocument1. For this we can use documentInStages_every.
Keeping in mind that a document entry can exist in multiple stages, the difference between documentInStages_some and documentInStages_every is that documentInStages_some checks if an entry exists in a particular stage, whereas by using documentInStages_every we request an entry that exists in only and exactly that stage. So if we use documentInStages_every with PUBLISHED the query will return results only if the document exists in PUBLISHED and no other stage.
You might read this and try a query such as the following:
where:{
documentInStages_every:{
stage:PUBLISHED
}
}
While you are on the right track, this will unfortunately return no results. The reason is that, as we mentioned earlier, every document always exists in DRAFT, so no document will ever only exist in PUBLISHED.
If you try changing the above PUBLISHED to DRAFT, however, you will get cldocument2 as a result, as this document only exists in the DRAFT stage.
As a workaround for this problem, we can use the OR meta filter, by using the following query:
where:{
documentInStages_every:{
OR:[
{
stage:DRAFT
},
{
stage:PUBLISHED
}
]
}
}
Since the internal query is that the stage must exist either in DRAFT or PUBLISHED, the query evaluates to true for both document cldocument1 and cldocument2. It skips cldocument4, which is what we want, but we still get cldocument2 which exists only in DRAFT.
We can use the same pattern of using meta filters to filter out the DRAFT entry. Let's start by writing this query:
where:{
NOT:[
{
documentInStages_every:{
stage:DRAFT
}
}
]
}
As you can see, this query returns any document that does not exist only in DRAFT, Which in this case would be cldocument1 and cldocument4. If we were to do an intersection of the results of the above two queries, we would get cldocument1, which is the document that we want.
In order to do this, we combine the above two queries to create the following:
where:{
AND:[
{
documentInStages_every:{
OR:[
{
stage:DRAFT
},
{
stage:PUBLISHED
}
]
}
},
{
NOT:[
{
documentInStages_every:{
stage:DRAFT
}
}
]
}
]
}
As you can see above, by using the AND meta filter we get the intersection between the two queries above, which returns the cldocument1 document.
compareWithParent
compareWithParent allows the comparison of a document with its parent entry using any comparison operators available within it.
At the moment compareWithParent is available only inside a documentInStages_* filter, and only allows the use of one attribute which is outdated_to. This attribute can be found inside the compareWithParent filter. The attribute is used to specify if we wish to check whether the child document is outdated compared to the parent document. For example:
variousDocuments(
stage:DRAFT
where:{
documentInStages_some:{
stage:PUBLISHED
compareWithParent:{
outdated_to:true
}
}
}
)
In the above example, we enable the filter by setting outdated_to to true - if it were set to false, it would be the same as having the filter omitted entirely. The true and false values are simply indicators of whether to process the filter in the query.
In the above query, we check if the child PUBLISHED version is outdated compared to the DRAFT parent version. At the moment, we check if a document is outdated by comparing the updatedAt attributes of both the DRAFT and PUBLISHED versions. If the DRAFT has a greater updatedAt, that means the document has been modified since it was last published, and is therefore considered outdated.
You can filter the data in your JSON fields by using json_path_exists syntax from PostgreSQL.
To be able to query this content, you need to know the JSON structure to navigate through it.
If you're not familiar with the structure, you can query for all content - without passing a filter, or with just a pagination filter depending on number of entries - and look into it. A great way to go about this kind of exploration is using the API Playground, where you can type “json” then use ctrl + space or command + space to display all the filters you can use and select one.
Please note that if the content data is in a JSON field that allows multiple values, the query will return the complete list.
Please note that in the query examples below, we escape the quotes with a backslash, like this \”. This is because the query is already inside double quotes, so any additional quotes require this format.
Query by quantity
You can use "$[*].** ? (@ > N)” to filter all values all for integers above a certain number. Just replace N with the number of your choice.