Discussion on syncing user data and customizing the Sanity studio based on user access.
I understand you want to automatically create user documents for all project members each time the Studio loads. Unfortunately, the links you referenced appear to be broken or moved, but I can help you solve this problem.
The challenge you're facing is that certain hooks (like the one that might create initial documents) don't work with custom desk structures. Here are a few approaches to solve this:
Solution 1: Use a Studio Plugin with Layout Component
Instead of relying on desk structure lifecycle, create a Studio plugin that runs initialization logic when the Studio mounts:
// plugins/userDocumentSync.js
import {definePlugin} from 'sanity'
import {useEffect} from 'react'
export const userDocumentSync = definePlugin({
name: 'user-document-sync',
studio: {
components: {
layout: (props) => {
useEffect(() => {
// Fetch project members and sync user documents
syncUserDocuments()
}, [])
return props.renderDefault(props)
}
}
}
})
async function syncUserDocuments() {
const client = sanityClient.withConfig({apiVersion: '2024-01-01'})
// Fetch project members using Management API
const members = await fetch(
`https://api.sanity.io/v2021-06-07/projects/${projectId}/members`,
{headers: {Authorization: `Bearer ${token}`}}
).then(res => res.json())
// Create/update documents for each member
for (const member of members) {
await client.createIfNotExists({
_id: `user.${member.id}`,
_type: 'user',
name: member.displayName,
email: member.email
})
}
}Then add this plugin to your sanity.config.js:
import {userDocumentSync} from './plugins/userDocumentSync'
export default defineConfig({
// ...
plugins: [
// ... other plugins
userDocumentSync()
]
})Solution 2: Use Sanity Functions (Recommended)
For a more robust solution that doesn't depend on Studio loading, use Sanity Functions with a scheduled trigger:
// sanity.blueprint.ts
import {defineBlueprint} from '@sanity/blueprint'
export default defineBlueprint({
functions: [
{
name: 'sync-user-documents',
runtime: 'node22',
schedule: '0 * * * *', // Run hourly
handler: async (event) => {
// Fetch members from Management API
// Sync to dataset
}
}
]
})This approach is better because:
- It runs independently of Studio
- Works even when no one has the Studio open
- More reliable and scalable
- Can be triggered on schedules or via webhooks
Solution 3: Tool Menu Action
Add a manual sync action to the Studio's tool menu that users can trigger when needed:
// tools/syncUsers.js
import {definePlugin} from 'sanity'
export const syncUsersTool = definePlugin({
name: 'sync-users-tool',
tools: [
{
name: 'sync-users',
title: 'Sync Users',
component: SyncUsersComponent
}
]
})Key Points
- Custom desk structures bypass some Studio lifecycle hooks, which is why your approach wasn't working
- Sanity Functions are the modern, recommended approach for automation like this - they run independently of Studio and can be triggered on schedules or events
- You'll need to use the Sanity Management API to fetch project members at
https://api.sanity.io/v2021-06-07/projects/{projectId}/members - Consider using
createIfNotExists()to avoid duplicates - The plugin layout component approach (Solution 1) will work for your specific "sync on Studio load" requirement, but Functions (Solution 2) provide a more reliable solution
The plugin with layout component wrapper is your best bet for the "run every time Studio loads" requirement with a custom desk structure. It works by wrapping the entire Studio layout rather than hooking into the desk structure specifically.
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.