How to get the currently logged in user inside a Sanity schema

16 replies
Last updated: Dec 12, 2022
https://www.sanity.io/docs/migration-cheat-sheet#713ae1bbd4d3 This is still confusing me. I simply need the currently logged in user inside of a schema.

import {useClient, useCurrentUser} from 'sanity'

const GetUserRoles = () => {
    const user = useCurrentUser()
    const {roles} = user
    return roles
}
This doesn't work. Also,
this doesn't look right.
user
!==
currentUser
, must be a typo.Also, this gives an error... it wants export function
MyComponent () {
Is this a typescript shortcut or something?

export function MyComponent {
  const user = useCurrentUser()
  const {id, name, email, profileImage, provider, roles} = currentUser

  return <div>JSX</div>
}
AI Update

You're absolutely right to be confused - there is indeed a typo in the official documentation on that page. Good catch! Let me clear this up:

The Problem in the Docs

The migration cheat sheet shows:

export function MyComponent {  // ❌ Missing parentheses
  const user = useCurrentUser()
  const {id, name, email, profileImage, provider, roles} = currentUser  // ❌ Wrong variable name
  return <div>JSX</div>
}

There are two errors here:

  1. Missing () after MyComponent - it needs to be a proper function declaration
  2. Destructuring from currentUser when the variable is actually named user

The Correct Way

Here's how to properly use useCurrentUser() in a React component:

import {useCurrentUser} from 'sanity'

export function MyComponent() {  // ✅ Needs parentheses
  const currentUser = useCurrentUser()  // ✅ Can name it whatever you want
  
  // currentUser can be null, so handle that:
  const {id, name, email, profileImage, provider, roles} = currentUser ?? {}
  
  return <div>JSX</div>
}

Key points:

  • export function MyComponent() needs parentheses - this is standard JavaScript function syntax, not a TypeScript shortcut
  • The hook returns a user object that you can name anything (user, currentUser, etc.)
  • useCurrentUser() returns CurrentUser | null, so use optional chaining (?.) or nullish coalescing (??) to handle the null case

Using Current User in Schema Definitions

Your original code won't work because you cannot use React hooks directly in schema files. Schemas are configuration objects, not React components.

Instead, access currentUser through the context parameter in field-level functions:

export default {
  name: 'myDocument',
  type: 'document',
  fields: [
    {
      name: 'restrictedField',
      type: 'string',
      hidden: ({currentUser}) => {
        // currentUser is available in the context
        return !currentUser?.roles?.some(role => 
          role.name === 'administrator'
        )
      }
    }
  ]
}

The currentUser object in schema contexts has the same shape: {id, name, email, profileImage, provider, roles}.

This is mentioned in the Sanity docs on conditional fields, where currentUser is one of the parameters available to functions like hidden, readOnly, and initialValue.

That's usually available in the
context
passed to certain parts of the schema. What are your trying to do with the current user?
I'm trying to control how the array is built for an array field. It's a page builder, so only certain roles can add certain types of page components. I really don't need a Custom Input Component, so I'm trying to avoid that.
Can you share how you currently have this implemented in a V2 studio (if you have it) or what you have so far?
It wasn't possible in the V2 studio without creating a custom input component, actually, but I can show you some of the V3 code:
//array
const pageBlocks =
    [
        {type: "aDayInTheLifeBlock", title: "A Day In The Life"},
        {type: "beyondTheClassroomBlock", title: "Beyond The Classroom"},
        {type: "careerBlock", title: "Career Block"},
        {type: "cta", to: [{type: "cta"}], title: "Call to Action"},
            ....
    ]

//schema field

{
    group: "content",
        name: "contentBlocks",
    title: "Content Blocks",
    type: "array",
    of: pageBlocks
},
   

Got it. The current user isn't provided to your schema like this and you can't use asynchronous code when defining your schema, so you wouldn't be able to fetch the current user. I'm afraid you'll have to use a custom input component, fetch the current user, filter your
pageBlocks
array based off of their role, then use the
renderDefault
option to display the default input component for that list. I can help you put it together if you need!
There are examples in the v3 migration guide for Custom Input Componens using string and object, but not array. Is there an example somewhere?
I don't think there is actually. I can try to put one together this afternoon, though.
Try, I can also try to work through one.
But I wonder: will it look exactly the same as the default type?
This has been a feature I've been wanting since forever, so I'm trying to make it happen.
Yeah, the renderDefault function just renders the original input so it should look the same as the default type.
Ok, thanks.
Ok, here's an example:
{
      name: 'contentBlocks',
      title: 'Content Blocks',
      type: 'array',
      of: pageBlocks,
      components: {
        input: RolesBasedArrayInput,
      },
    },

import React from 'react'
import {useCurrentUser} from 'sanity'

export function RolesBasedArrayInput(props) {
  const {schemaType, renderDefault} = props
  const {role} = useCurrentUser()

  const allowedTypes =
    role == 'administrator'
      ? schemaType.of
      : schemaType.of.filter((type) => !['aDayInTheLifeBlock', 'careerBlock'].includes(type.name))

  return <>{renderDefault({...props, schemaType: {...schemaType, of: allowedTypes}})}</>
}
Oh wow, thanks!
You're welcome!

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.

Was this answer helpful?