Migrating from Sanity version 2 to 3, encountering issue with using the sanity client in a React function.

1 replies
Last updated: May 24, 2023
I am migrating from version two version three and I’m running into a problem with the sanity client. It used to just look like this.
import sanityClient from 'part:@sanity/base/client';
Now we have to use the react hook from this

import {useClient} from 'sanity'
But the problem is when I try to do something like this

const client = useClient({apiVersion: '2023-05-24'});
I get an error because react hooks cannot be used at the top level

React Hook “useClient” cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function.
The issue is that my previous code isn’t using the sanity client in a react function or component. It’s just using it at top level
AI Update

Good news - you don't need to use the useClient hook for top-level code! The hook is only for React components, but Sanity v3 provides other ways to get a client depending on your context.

For non-React contexts (Structure Builder, Document Actions, etc.)

When you're working in places like the Structure Builder, document actions, initial value templates, or other configuration code, you should use the context.getClient() method instead. These contexts receive a context object that includes a getClient() method:

// In document actions
export function myDocumentAction(props) {
  return {
    label: 'My Action',
    onHandle: () => {
      const client = props.context.getClient({ apiVersion: '2023-05-24' })
      // Use client here
    }
  }
}

// In Structure Builder
export const structure = (S, context) => {
  const client = context.getClient({ apiVersion: '2023-05-24' })
  // Use client to fetch data for your structure
  return S.list()...
}

According to the Document Actions API documentation, the context object includes a getClient function that "returns a configured SanityClient."

For completely standalone code

If you need a client outside of Studio contexts entirely (like in a separate utility file), you can create a standalone client using createClient from @sanity/client:

import { createClient } from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  apiVersion: '2023-05-24',
  useCdn: false,
  token: 'your-token' // if needed
})

When to use each approach

  • useClient hook: Only inside React components (custom input components, tools, etc.)
  • context.getClient(): In Studio configuration contexts (document actions, structure builder, initial values, etc.)
  • createClient: For standalone scripts or utilities outside Studio

The key difference from v2 is that the part:@sanity/base/client pattern has been removed. Instead, v3 provides context-appropriate ways to access the client based on where you're working. As mentioned in the useClient documentation, this ensures proper integration with the studio's configured client instance.

It depends on where you’re doing this, but most of the methods within the Studio receive a
context
in its props that contains a client you can use.

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?