Best way to model recursively nested documents in Sanity?

6 repliesLast updated: Nov 29, 2025

I’m sure this has been asked a bunch of times, but what’s the best solution for modelling a recursively nested document. So for example a “region” content type that could have any number of children or grandchildren to achieve a nested document structure like this:
UK => England => Oxfordshire
,
UK => Gibraltar
or
USA => Washington
AI Update

You're right, this is a common question! For your nested region structure (UK → England → Oxfordshire), the most straightforward approach is to use self-referencing documents with a parent reference field.

Here's how to model it:

export default defineType({
  name: 'region',
  type: 'document',
  fields: [
    {
      name: 'name',
      type: 'string',
      title: 'Region Name'
    },
    {
      name: 'parent',
      type: 'reference',
      title: 'Parent Region',
      to: [{type: 'region'}],
      // Optional: helps prevent circular references
      validation: Rule => Rule.custom((parent, context) => {
        if (parent?._ref === context.document?._id) {
          return 'A region cannot be its own parent'
        }
        return true
      })
    }
  ]
})

With this structure:

Querying the hierarchy

To fetch a region with all its children, you can use GROQ:

*[_type == "region" && _id == $regionId][0]{
  _id,
  name,
  "children": *[_type == "region" && parent._ref == ^._id]{
    _id,
    name
  }
}

For the full tree from a root region, you'd need to query recursively or fetch all regions and build the tree client-side.

Alternative: Array of children

You could also model this top-down with an array of child references:

{
  name: 'children',
  type: 'array',
  of: [{type: 'reference', to: [{type: 'region'}]}]
}

However, the parent reference approach is generally better because:

The parent reference approach scales well for unlimited nesting depth. Just be mindful that very deep hierarchies might require multiple queries or client-side tree building for full traversal. Sanity naturally supports these graph-like content structures through its reference system, making it flexible for complex hierarchical relationships.

Show original thread
6 replies

Was this answer helpful?

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Related contributions