`client.fetch` is not a function in `resolveProductionUrl` Sanity Studio v3

2 repliesLast updated: Dec 1, 2025

Hi everyoneIm trying to generate a link to a production environment for preview in studio v3. Im using this guide
https://www.sanity.io/docs/preview-content-on-site .
But I keep getting the error:

error was thrown while trying to get your preview url: An error occurred while resolving `resolveProductionUrl`: client.fetch is not a function. (In ‘client.fetch(
*`*[_id == $postId][0].slug.current`,*
{postId: document._id}
)’, ‘client.fetch’ is undefined
My code looks like this:
productionUrl: async (prev, context) => {
      // context includes the client and other details
      const {client, dataset, document} = context

      if (document._type.includes('page')) {
        const slug = await client.fetch(
          `*[_id == $postId][0].slug.current`,
          {postId: document._id}
        )

        console.log(document._id)
        const params = new URLSearchParams()
        params.set('preview', 'true')
        params.set('dataset', dataset)

        return `<https://my-domain.com/${slug}?${params}>`
      }

      return prev
    },

AI Update

The error you're seeing happens because in Sanity Studio v3, the context object passed to productionUrl doesn't directly include a client with a fetch method. Instead, you need to use getClient() to create a client instance.

Here's the fix for your code:

productionUrl: async (prev, context) => {
  const {getClient, dataset, document} = context
  const client = getClient({ apiVersion: '2023-06-27' })

  if (document._type.includes('page')) {
    const slug = await client.fetch(
      `*[_id == $postId][0].slug.current`,
      {postId: document._id}
    )

    console.log(document._id)
    const params = new URLSearchParams()
    params.set('preview', 'true')
    params.set('dataset', dataset)

    return `https://my-domain.com/${slug}?${params}`
  }

  return prev
}

The key change: Replace const {client, dataset, document} = context with const {getClient, dataset, document} = context, then call getClient() to create your client instance.

However, there's actually a simpler approach that doesn't require fetching at all. Since the document object in the context already contains all the document's fields, you can access the slug directly:

productionUrl: async (prev, context) => {
  const {document, dataset} = context

  if (document._type.includes('page')) {
    const slug = document.slug?.current
    
    if (!slug) {
      return prev
    }

    const params = new URLSearchParams()
    params.set('preview', 'true')
    params.set('dataset', dataset)

    return `https://my-domain.com/${slug}?${params}`
  }

  return prev
}

This second approach is recommended because:

The getClient() approach is only necessary if you need to query for data that isn't on the current document (like fetching related documents or doing more complex queries).

This is a known issue that was discussed in the Sanity community, and the documentation has since been updated to reflect the correct v3 API.

Show original thread
2 replies

Was this answer helpful?

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.

Related contributions