Migrating resolveProductionUrl from Sanity v2 to v3

6 replies
Last updated: Jan 30, 2023
Hi All. I'm upgrading a studio to v3 and it's all working apart from the production previews. In v2 I was using (resolveProductionUrl.js):
export default function resolveProductionUrl(document) {

if (document._type == "page"){
`return `
https://sitename.netlify.app/page-preview/${document._id} ``
}

if (document._type == "product"){
`return `
https://sitename.netlify.app/product-preview/${document._id} ``
}

if (document._type == "post"){
`return `
https://sitename.netlify.app/post-preview/${document._id} ``
}

}
But I'm struggling to get it working now. I find the migration docs difficult to understand in this area. Could anyone point me in the right direction? Thanks in advance!
AI Update

I'll help you migrate your production preview URL from Sanity Studio v2 to v3. The migration docs can be confusing, but the good news is that the concept is similar - it just needs to be configured in a different location.

The Migration

In Studio v3, the resolveProductionUrl functionality has been replaced by the productionUrl property in your sanity.config.ts (or .js) file. Here's how to migrate your v2 code:

Your v2 code:

// resolveProductionUrl.js
export default function resolveProductionUrl(document) {
  if (document._type == "page"){
    return `https://sitename.netlify.app/page-preview/${document._id}`
  }
  if (document._type == "product"){
    return `https://sitename.netlify.app/product-preview/${document._id}`
  }
  if (document._type == "post"){
    return `https://sitename.netlify.app/post-preview/${document._id}`
  }
}

Your v3 code:

// sanity.config.ts (or .js)
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'

export default defineConfig({
  projectId: '<your-project-id>',
  dataset: 'production',
  plugins: [structureTool()],
  schema: {
    types: schemaTypes,
  },
  document: {
    productionUrl: async (prev, context) => {
      const {document} = context
      
      if (document._type === "page") {
        return `https://sitename.netlify.app/page-preview/${document._id}`
      }
      if (document._type === "product") {
        return `https://sitename.netlify.app/product-preview/${document._id}`
      }
      if (document._type === "post") {
        return `https://sitename.netlify.app/post-preview/${document._id}`
      }
      
      return prev
    }
  }
})

Key Differences

  1. Location: It's now configured in the document property of your main config, not a separate file
  2. Function signature: The function receives (prev, context) where the document is available as context.document
  3. Return fallback: You should return prev if none of your conditions match
  4. Can be async: The function can be async if you need to do any asynchronous operations

Alternative: Using document slug

If you're using slugs instead of IDs for your preview URLs, you can access them like this:

productionUrl: async (prev, context) => {
  const {document} = context
  const slug = document?.slug?.current
  
  if (!slug) return prev
  
  if (document._type === "page") {
    return `https://sitename.netlify.app/page-preview/${slug}`
  }
  // ... rest of your conditions
}

The preview button should now appear in your document actions bar when editing documents of these types. You can read more about configuring productionUrl in the Studio configuration docs.

Hope this helps with your v3 upgrade!

Show original thread
6 replies
Okay, to be more precise, in the migration docs it has this example:

document: {
    // prev is the result from previous plugins and can be composed
    productionUrl: async (prev, context) => {
      // context includes the client an other details
      const {client, dataset, document} = context

      if (document._type === 'post') {
        // you can now use async/await πŸŽ‰
        const slug = await client.fetch(
          `*[_type == 'routeInfo' && post._ref == $postId][0].slug.current`,
          {postId: document._id}
        )

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

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

      return prev
    },
  },
})
How can I modify this if I just want to query by document._id rather than slug?
Something like this should work:
document: {
    // prev is the result from previous plugins and can be composed
    productionUrl: async (prev, {document}) => {

      if (document._type == "page"){
    return `<https://sitename.netlify.app/page-preview/${document._id}>`
    }
    if (document._type == "product"){
      return `<https://sitename.netlify.app/product-preview/${document._id}>`
      }
    if (document._type == "post"){
        return `<https://sitename.netlify.app/post-preview/${document._id}>`
        }
  }

      return prev
    },
  },
})
Thanks so much for the reply. I can see you have a tidal wave of support queries to deal with! πŸ™
This is all working now. I left out the:
 return prev
Fully upgraded to v3 now, thanks again for the support!
Congrats on finishing your migration!
Thanks! I'm impressed with V3. Everything is so fast now. Onwards! πŸš€

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?