
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThis is definitely achievable! You have a couple of solid approaches. For automatic syncing, I'd recommend using Sanity Functions, which are serverless functions that run on Sanity's infrastructure and respond to document changes.
Sanity Functions let you execute custom logic whenever changes occur in your content without requiring your own infrastructure. When an Artwork is created or updated with an Artist reference, a function can automatically update that Artist document to include the reference back.
Here's how to set this up. First, initialize Blueprints in your project (requires Sanity CLI v3.92.0+, v4.5.0+ recommended):
npx sanity blueprints init
npx sanity blueprints add function --name sync-artwork-to-artistThis creates a sanity.blueprints.ts file and a function directory. Here's what your configuration might look like:
// sanity.blueprints.ts
import {defineBlueprint, defineDocumentFunction} from '@sanity/blueprints'
export default defineBlueprint({
resources: [
defineDocumentFunction({
type: 'sanity.function.document',
name: 'sync-artwork-to-artist',
src: './functions/sync-artwork-to-artist',
event: {
on: ['create', 'update'],
filter: '_type == "artwork" && defined(artist._ref)',
},
}),
],
})Then create your function handler:
// functions/sync-artwork-to-artist/index.ts
export default async function(event, context) {
const { getClient } = context
const client = getClient({ apiVersion: '2024-01-01' })
const artwork = event.document
if (artwork.artist?._ref) {
// Check if this artwork reference already exists to avoid unnecessary updates
const artist = await client.getDocument(artwork.artist._ref)
const existingRefs = artist.artworks || []
const alreadyExists = existingRefs.some(ref => ref._ref === artwork._id)
if (!alreadyExists) {
await client
.patch(artwork.artist._ref)
.setIfMissing({ artworks: [] })
.append('artworks', [{ _type: 'reference', _ref: artwork._id }])
.commit()
}
}
}Deploy with:
npx sanity blueprints deploySimilarly, you could create a function that watches for changes to Exhibition documents and updates the related Artist records when artworks are added to exhibitions. The pattern would be the same—listen for exhibition updates, extract the artwork references, look up which artists created those works, and update the artist documents accordingly.
Before going the automation route, seriously consider whether you actually need to store these bidirectional references. You can query for reverse references using GROQ without storing them:
// Get all artworks by this artist
*[_type == "artwork" && artist._ref == $artistId]
// Get all exhibitions featuring this artist's work
*[_type == "exhibition" && references(*[_type == "artwork" && artist._ref == $artistId]._id)]This approach keeps your data normalized and avoids the complexity of keeping bidirectional references in sync. You only store references in one direction and query for the reverse relationship when needed. It's simpler, less prone to data inconsistencies, and easier to maintain.
The Functions approach makes sense if you need extremely fast reads and can accept slightly slower writes, or if you need to trigger additional side effects when these relationships change. The query approach is simpler and keeps your data model cleaner.
Experimental feature: Blueprints are currently experimental, so the APIs may change.
Avoid recursive loops: Functions don't currently prevent recursive loops, so be careful when writing functions that modify documents. In the example above, I added a check to only update the artist if the artwork reference isn't already present—this prevents the function from repeatedly triggering itself.
Testing: You can test your functions locally before deploying:
npx sanity functions test sync-artwork-to-artist --dataset productionThe bidirectional reference syncing is definitely achievable with Functions, but I'd encourage you to start with the query-based approach unless you have specific performance requirements that demand pre-computed relationships.
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