Skip to content
Now accepting new projects — limited slots available. Get started →
CMS · Updated Aug 2, 2026

What is GROQ (Sanity Query Language)?

GROQ is a query language created by Sanity for filtering and projecting JSON documents from its content lake.

What is GROQ?

GROQ (Graph-Relational Object Queries) is an open-source query language Sanity.io built for filtering, projecting, and joining JSON documents in their content lake. It shipped in 2017 with Sanity's initial release. The syntax is pipeline-based, reads left to right — think chaining array methods in JavaScript. Unlike GraphQL, there's no schema definition or resolver layer. You query documents directly by _type and shape the response inline. Sanity open-sourced the spec in 2019. As of April 2026, they support GROQ version 2021-03-25 (sometimes called GROQ v2), which includes stuff like the score() function for full-text relevance ranking. We use GROQ on every Sanity project we ship. It's the default way to pull content into Next.js or Astro frontends through Sanity's CDN-backed API.

How it works

GROQ queries follow a pipeline pattern: start with everything, filter it down, project only the fields you need.

Basic query:

*[_type == "post" && publishedAt < now()] | order(publishedAt desc) [0...10] {
  title,
  slug,
  "authorName": author->name,
  "categoryTitles": categories[]->title,
  body
}

Breaking that down:

  • * — starts with all documents in the dataset
  • [_type == "post" && publishedAt < now()] — filter pipe: only published posts
  • | order(publishedAt desc) — sort pipe
  • [0...10] — slice pipe: first 10 results
  • { ... } — projection: shape the output

The -> operator dereferences a reference field. That's how GROQ handles joins. If author is a reference to a person document, author->name follows that reference and returns the name field. This works at arbitrary depth — author->company->name is valid.

GROQ queries hit Sanity's API over HTTPS at https://<projectId>.api.sanity.io/v2021-03-25/data/query/<dataset>. Responses come from Sanity's edge CDN when you use the apiCdn option — read latency is typically 30-80ms globally. You can also use GROQ inside Sanity Studio's Vision plugin to test queries interactively during development.

Parameters are passed separately to avoid injection:

*[_type == "post" && slug.current == $slug][0]

With { slug: "my-post" } as the params object.

When to use it

GROQ is the right choice when you're working with Sanity as your CMS. It's the first-class query language. GraphQL support in Sanity exists but it's auto-generated, less flexible, and doesn't support all the same operations (like score() or inline joins across more than one level).

Use GROQ when:

  • You're querying Sanity's content lake (it's the only context where GROQ runs)
  • You need flexible projections that change per page or component
  • You want to dereference nested references without N+1 problems
  • You're building ISR/SSG pages in Next.js or Astro and need predictable, CDN-cached responses

Don't use GROQ when:

  • Your CMS isn't Sanity — GROQ doesn't apply to Contentful, Strapi, or other platforms
  • You need write operations — GROQ is read-only; mutations use Sanity's Mutation API
  • You're doing heavy aggregation — GROQ has count() and math::sum() but it's not a replacement for SQL analytics

GROQ vs alternatives

The most common comparison is GROQ vs GraphQL, since Sanity offers both.

Feature GROQ GraphQL (Sanity) REST / Custom API
Schema required No Auto-generated from Sanity schema Depends on implementation
Joins / References -> operator, arbitrary depth Limited to 1 level by default Manual
Full-text scoring score() function built in Not supported Custom
Filtering Inline, any field Supported but less expressive Custom
Tooling Vision plugin, groq-js Apollo, Relay, etc. Varies
Caching CDN-backed via Sanity API CDN-backed via Sanity API Self-managed

Our take: if you're on Sanity, default to GROQ. It's more expressive for document-centric queries and avoids the overhead of maintaining a GraphQL layer you don't need. GraphQL makes sense if your frontend team already has a GraphQL client setup and needs to query multiple sources through a single gateway.

Real-world example

On a recent Next.js 15 + Sanity v3 project — a media company with ~12,000 articles — we used GROQ to power the homepage, category pages, and article pages. The homepage query pulled the latest 20 articles with dereferenced author and category data in a single GROQ call. Returned in ~45ms from Sanity's CDN. We used score() with boost() to build a search page that ranked results by both text relevance and recency without needing Algolia. The entire data-fetching layer was about 15 GROQ queries total, each co-located with its page component. Using groq-js (Sanity's JavaScript GROQ evaluator), we also ran GROQ queries client-side against Sanity's real-time listener for live preview in the Studio. No separate preview API needed.

Frequently asked questions about GROQ (Sanity Query Language)

Is GROQ the same as GraphQL?
No. GROQ and GraphQL are fundamentally different query languages. GraphQL is a specification maintained by the GraphQL Foundation that works across any backend with a resolver layer and schema definition. GROQ is a domain-specific language created by Sanity.io that only runs against Sanity's content lake. GROQ doesn't require a schema, uses a pipeline syntax instead of GraphQL's nested selection sets, and supports features like the `->` dereference operator for following document references. Sanity does offer a GraphQL API alongside GROQ, but GROQ is more expressive within the Sanity context — it supports deeper joins, full-text scoring, and more flexible filtering.
When did GROQ become standard for Sanity?
GROQ has been the default query language for Sanity since Sanity's public launch in 2017. The specification was formally open-sourced in 2019 under Sanity's GitHub organization. The current stable version is dated 2021-03-25 (often called GROQ v2), which introduced features like the `score()` function, `math::` and `string::` namespaced functions, and improved syntax for conditional projections. Every version of the Sanity API since v1 has supported GROQ as the primary query method, and the Vision plugin for testing GROQ queries has been bundled with Sanity Studio since Studio v2.
What's the alternative to GROQ for querying Sanity?
Sanity also exposes an auto-generated GraphQL API that you can deploy per dataset. It's created from your Sanity schema and supports basic filtering and ordering. However, it has limitations compared to GROQ: joins only work one level deep by default, there's no `score()` equivalent for full-text relevance, and you can't do inline computed fields. Outside of those two, you could also use Sanity's export API to dump your entire dataset and query it locally with any tool — we've done this for data migrations using `jq` or Node scripts. But for production page rendering, GROQ through the CDN API is the standard path.
Can GROQ be used outside of Sanity?
Technically, yes — Sanity open-sourced the `groq-js` package, which is a JavaScript implementation of the GROQ specification that can evaluate queries against any array of JSON objects in memory. You could use it to filter local data. However, in practice, nobody does this at scale. GROQ's real value comes from running against Sanity's hosted API with its CDN caching, indexing, and real-time subscription support. Using `groq-js` locally is mainly useful for testing, live previews in Sanity Studio, or validating query logic in unit tests. We wouldn't recommend adopting GROQ as a general-purpose query language outside the Sanity ecosystem.
Get in touch

Let's build
something together.

Whether it's a migration, a new build, or an SEO challenge — the Social Animal team would love to hear from you.

Get in touch →