
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeGreat question! For your hierarchical URL structure like country/state/county/city, you're on the right track thinking about references. Let me walk you through the most recommended approaches.
For your hierarchy, the most flexible approach is to create separate document types for each level and connect them with reference fields. You have two main options:
Each document references its parent:
// city.js
{
name: 'city',
type: 'document',
fields: [
{name: 'name', type: 'string'},
{name: 'slug', type: 'slug'},
{
name: 'county',
type: 'reference',
to: [{type: 'county'}]
}
]
}
// county.js references state, state references country, etc.Pros:
Each document contains arrays of references to its children:
// country.js
{
name: 'country',
type: 'document',
fields: [
{name: 'name', type: 'string'},
{name: 'slug', type: 'slug'},
{
name: 'states',
type: 'array',
of: [{type: 'reference', to: [{type: 'state'}]}]
}
]
}Pros:
Regardless of which direction you choose, you can build full paths using GROQ queries. For a bottom-up structure:
*[_type == "city" && slug.current == $slug][0] {
name,
"path": slug.current,
county-> {
name,
"path": slug.current,
state-> {
name,
"path": slug.current,
country-> {
name,
"path": slug.current
}
}
}
}The -> operator follows references, and because references are bidirectional when queried, you can traverse them from either direction.
An important thing to know: references are only visible in the Studio UI where the reference field is defined. So if you use bottom-up references, the city document will show the county reference field, but the county document won't show which cities reference it in the UI (though you can still query this relationship using the references() function).
You mentioned using a singleton document to manage the hierarchy. This is usually unnecessary and adds complexity. The reference structure itself creates the hierarchy, and you can query it dynamically. A singleton would only be useful if you need to manually curate or order the hierarchy in a specific way.
However, if you need to create navigation menus that differ from your content structure, the Table of Contents pattern can be useful. This lets you provide different hierarchical views for different audiences without changing your core content structure.
For simpler cases, you could also store the full path in each document's slug (e.g., usa-georgia-fulton-atlanta) and use string manipulation in your frontend. This is less flexible but might work if your hierarchy is relatively flat and doesn't change often.
The reference-based approach gives you the most flexibility and aligns well with Sanity's graph-like content organization, making it the recommended pattern for your use case!
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store