Skip to content
Join our next Developer Virtual Meetup – Live Q&A, Project Showcase, Swag raffle, and more 🔥
Sanity
    • Platform

      Sanity Studio

      Flexible editing environment

      APIs

      Connect to anything

      Content Lake

      Fully decoupled back end

      Try product demo

      Features

      Real-time collaboration

      Fearlessly work with content

      Precise content querying

      Treat content as data with GROQ

      Localization

      Coherent messaging across territories

    • Use cases

      E-commerce

      Richer shopping experiences

      Marketing sites

      Control your story

      Products & services

      Innovate and automate

      Mobile apps

      Content backend for every OS

      View all

      Integrations

      Shopify
      Mux
      Vercel
      Netlify
      Algolia
      Cloudinary
      BigCommerce
      Commerce Layer
      Smartling
      Transifex
      View all
    • Learn

      Documentation
      Studio API Reference
      API reference
      Guides
      GROQ cheat sheet
      Sanity UI
      Get started

      Build and share

      Templates
      Tools and plugins
      Schemas and snippets
      Project showcase
      Share your work
      Browse Exchange

      Frameworks

      React
      Vue
      Next.js
      Nuxt.js
      Svelte
      Remix
      Gatsby
      Astro
      Angular
      Eleventy
      View all
    • Discover

      Blog
      Resource library
      Glossary
      Agency partners
      Become a partner
      Technical support
      Talk to sales

      Case studies

      Puma

      Source of truth for global markets

      Aether

      Unique digital shopping experience

      Morning Brew

      Omnichannel media distribution

      InVision

      Delivering exceptional customer experiences

      View all

      Popular guides

      Headless CMS
      Structured content
      Content modeling
      Headless SEO
      Static websites
      View all
    • Enterprise
    • Pricing
    • Log in
    • Contact sales
    • Get started
Contact salesGet started
Published July 9th 2019

We’re open sourcing GROQ: A query language for JSON documents

Today we’re open sourcing the specification for Sanity’s query language GROQ.

Knut Melvær

Head of Developer Community and Education

Today we’re open sourcing the spec for Sanity’s query language GROQ. We’re also developing tooling so you can use its powerful features for filtering, projection and sorting anywhere you might be stuck with JSON document collections.

So what can you use GROQ for? Say you have a perplexing urge to filter and transform those 20,000 posts sitting in a Sanity dataset. First of all you really only want the ones with “JavaScript” in the title. And oh, you only need those with more than four code examples in the body text. And you don’t need all the fields – just titles, and the name of the referenced authors. And yeah, order the results by publish date while you’re at it, HAL.

The following is how you would do this today with Sanity’s query language GROQ:

// indented for readability
*[
  title match "Javascript" 
  && count(body[_type == "code"]) > 4
]{
  title, 
  authors[]->{name}
}|order(publishedAt asc)

GROQ is short for for Graph-Relational Object Queries. GROQ was born out of the development of our real-time document store that Simen Svale Skogsrud and Alexander Staubo started developing in 2015. Erik Grinaker has since then contributed with follow-up work on consistency. Magnus Holm has recently started work on building a parser toolkit that lets us easily build GROQ parsers in different languages.

As of today, millions of GROQ queries serve content from Sanity every day to websites, apps, and other systems. As GROQ is a wholesome way of quering and reshaping collections of JSON documents it’s generally useful and doesn’t need to be tied to our systems.

Now that GROQ has been in production for a while, and we are pinning down how we want it to work, it’s therefore also time to open source our work with it.

Check out our introduction to GROQ, and the specification, and the CLI tool.

The specification

To kick off the open sourcing of GROQ we are publishing the working draft of the GROQ specification. While we have thorough reference documentation for how GROQ works with our hosted content store, there are still some corners we want to sort out before bumping the spec to 1.0. We obviously didn’t get everything right on the first try. The specification allows for implementations to add additional features and functions. For example, with Sanity we have added the identity() function to be able to query with user permissions.

Of course, the specification is also written and stored in our Sanity project. We took inspiration from GraphQL’s specification and use GraphQL’s creator Lee Byron’s excellent spec-md to generate the user-friendly website for this. It’s done with a small script that fetches the documents from Sanity, and converts them into the Markdown-files that checked into the GitHub repository.

You are welcome to post questions in the repository, and we will answer them on a best effort basis.

The Parser and the CLI

Our new backend engineer, Magnus Holm, has done some pretty interesting work recently with parsing technologies and is working on Glush, a “parser-parser”, that we can use to generate a GROQ parser (or parser for other languages). So we generated one for JavaScript that you can run in Node or the browser. This opens for all sorts of interesting use cases that we can’t wait to explore.

We have wrapped the parser into a CLI tool that lets you query (ND)JSON from a file, a URL, or from standard input (that is, when you pipe data from another command). Let’s say you want to quickly output only the title of the todos that hasn’t been completed from an API, you can do something like this:

> curl -s https://jsonplaceholder.typicode.com/todos | groq "*[completed == false]{title}" --pretty
[
  {
    "title": "delectus aut autem"
  },
  {
    "title": "quis ut nam facilis et officia qui"
  },
  {
    "title": "fugiat veniam minus"
  },
  {
    "title": "laboriosam mollitia et enim quasi adipisci quia provident illum"
  },
  {
    "title": "qui ullam ratione quibusdam voluptatem quia omnis"
  },
  {
    "title": "illo expedita consequatur quia in"
  },
  {
    "title": "molestiae perspiciatis ipsa"
  },
  {
    "title": "et doloremque nulla"
  },
  // ...
]

This is only a simple example. There’s way more stuff you can do with GROQ. Let’s say you quickly wanted to count the grass and posion Pokemón from the Pokedex:

$ groq '{ "grass": count(*["Grass" in type]), "posion": count(*["Posion" in type])}' \
  --url https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json \
  --pretty --primary pokemon

> {
    "grass": 14,
    "posion": 33
  }

Or, let’s query the Nobel Prize API for female laureates for physics:

$ groq '*[gender == "female" && "physics" in prizes[].category]{firstname, surname}' \
  --url http://api.nobelprize.org/v1/laureate.json \
  --pretty --primary laureates
  
> [
    {
      "firstname": "Marie",
      "surname": "Curie, née Sklodowska"
    },
    {
      "firstname": "Maria",
      "surname": "Goeppert Mayer"
    },
    {
      "firstname": "Donna",
      "surname": "Strickland"
    }
  ]

We can also pipe a GROQ query to a new query, let’s say we wanted to count how many laureates in physics that have been men:

$ groq '*[gender == "male" && "physics" in prizes[].category]{firstname, surname}' \
  --url http://api.nobelprize.org/v1/laureate.json --primary laureates |groq 'count(*)'
  
> 206

What’s next?

As much as we try to avoid clichés, we have to point out that this is just the beginning for GROQ. We will continue working on the specification, and the tooling for it, making it even better and more capable. We are very excited about the prospect of running GROQ in the browser and what it can let us do for Sanity Studio and other applications. We hope it can be useful for you as well, and can’t wait to see what you’ll do with it.

Page content

  • The specification
  • The Parser and the CLI
  • What’s next?

Product

Sanity StudioAPIsContent LakeSecurity & Compliance
  • Sanity vs Contentful
  • Sanity vs Strapi
  • Sanity vs Wordpress
  • Sanity vs AEM
  • Sanity vs Hygraph
  • Sanity vs Sitecore
  • Sanity vs Storyblok
  • Sanity vs Contentstack
  • Sanity vs Prismic
  • Sanity vs Drupal
  • Sanity vs ButterCMS

Resources

DocumentationBlogResource libraryCase Studies
  • React Blog
  • Gatsby Blog
  • Next.js Landing Pages
  • Making a PWA
  • Single Page Application
  • Svelte & Typescript App
  • Vue & Tailwind Blog
  • Developer Portfolio Templates
  • Form validation with Yup
  • Live Preview with Next.js and Sanity.io
  • Next.js blog
  • Next.js personal website
  • Clean Next.js + Sanity app
  • Clean Remix + Sanity app
  • Clean SvelteKit + Sanity app
  • All Templates
  • Agency partners
  • Technology partners
  • Headless CMS 101
  • Static Sites 101
  • Headless Commerce 101
  • CMS for enterprise
  • Headless SEO
  • Localization
  • Content as a Service
  • What is a DXP?
  • Typescript 101
  • Ecommerce SEO
  • What is a Composable DXP?
  • What is an API?
  • GraphQL vs REST
  • React CMS
  • Next.JS CMS
  • CMS for Shopify
  • API-first CMS
  • Content platform
  • Multilingual CMS
  • Static Site CMS
  • Gatsby CMS
  • Node CMS
  • E-commerce CMS
  • Vue CMS
  • Angular CMS
  • GraphQL CMS
  • Newspaper CMS
  • Magazine CMS
  • CMS for apps
  • Remix CMS
  • Nuxt CMS
  • SvelteKit CMS
  • Agile CMS
  • Eleventy CMS
  • Multisite CMS

Company

Contact SalesEnterpriseCareersTerms of ServicePrivacy PolicyAccessibility Statement

Stay connected

  • GitHub
  • Slack
  • X.com
  • YouTube
  • Stack Overflow
  • Blog RSS
  • Newsletter
©Sanity 2024