Understanding getStaticProps and preview mode for a Next.js Sanity site

3 replies
Last updated: Jun 4, 2023
Could someone help me out with understanding getStaticProps and preview mode for a next.js sanity site? Both ends are deployed, I have a revalidate timer on getStaticProps, the only time new content comes up is when I redeploy. From what I'm reading I need to i @sanity/production-preview and have a preview file in both front and back to send and receive the url? Need to create a sanity.json file which I don't have one and I am unsure of what to fill it with. A helper function to get the client on preview mode for getStaticProps. A button function for the sanity studio so I could see the preview as well, is it necessary? Is that how I can have "ISR" I think and getStaticProps, have the content be loaded on the site with delay instead of having to redeploy everytime. Or would it be better that I use getServerSideProps? Wouldn't that be less optimized? Excuse the wall of text, or the dumb questions, I am trying to wrap my head around it.
AI Update

Good news - you're on the right track! Let me break down what you need to get ISR working and explain the preview/draft mode setup. No worries about the "wall of text" - these are great questions.

Why Your Content Isn't Updating

Your content only appears after redeploying because while you have a revalidate timer set, you're likely missing the most efficient approach: on-demand revalidation. Time-based revalidation works, but combining it with on-demand revalidation gives you the best of both worlds.

ISR vs SSR - Stick with ISR!

You're absolutely right to use getStaticProps with ISR instead of getServerSideProps. ISR is the better choice because:

  • Pages are served instantly from cache
  • Content updates automatically (with proper setup)
  • Much lower server costs and better performance
  • No need to rebuild your entire site

SSR with getServerSideProps would work but requires server computation on every request, which is slower and more expensive.

Setting Up ISR Properly

Basic Time-Based Revalidation

First, let's get your basic setup working. In your getStaticProps:

export async function getStaticProps() {
  const data = await client.fetch(YOUR_QUERY)
  
  return {
    props: { data },
    revalidate: 60 // Revalidate every 60 seconds
  }
}

This will update your content every 60 seconds - the first visitor after the revalidate period triggers a regeneration in the background.

On-Demand Revalidation (Better Approach)

Instead of just waiting for a timer, you can use on-demand revalidation to update pages immediately when content changes in Sanity. This is the recommended approach because it gives you immediate updates when editors hit "publish" while reducing unnecessary API requests.

1. Create an API route at pages/api/revalidate.js:

export default async function handler(req, res) {
  // Check for secret to confirm this is a valid request
  if (req.query.secret !== process.env.REVALIDATE_SECRET) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  try {
    // Revalidate the specific path
    await res.revalidate(req.query.path || '/')
    return res.json({ revalidated: true })
  } catch (err) {
    return res.status(500).send('Error revalidating')
  }
}

2. Set up a webhook in Sanity (in your project settings at sanity.io/manage) to trigger this API route when content changes. Point the webhook to https://yoursite.com/api/revalidate?secret=YOUR_SECRET&path=/your-page-path. This gives you immediate updates when editors hit "publish" without waiting for your revalidate timer.

This approach lets you use longer revalidate times (or even remove them) while still getting instant updates, reducing API requests and improving performance.

Preview Mode / Draft Mode (Separate from ISR)

Now for the preview setup - this is separate from ISR and lets editors see unpublished content. You're right that it involves both front and backend, but you don't need a sanity.json file for modern setups!

What You Actually Need

1. Create a preview-enabled client:

import { createClient } from 'next-sanity'

export const client = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
  apiVersion: '2024-01-01',
  useCdn: true,
})

export const previewClient = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
  apiVersion: '2024-01-01',
  useCdn: false,
  token: process.env.SANITY_API_TOKEN, // Read token from Sanity project settings
  perspective: 'previewDrafts', // This fetches draft content!
})

The perspective: 'previewDrafts' is crucial - it tells Sanity to prioritize draft documents over published versions, allowing you to see unpublished changes.

Important note on perspectives: Sanity offers several perspectives for different use cases:

  • published - Only published documents (good for production)
  • previewDrafts - Prioritizes drafts over published (perfect for preview mode)
  • raw - Returns everything, both drafts and published

2. Create an API route at pages/api/preview.js:

export default function handler(req, res) {
  // Check the secret and next parameters
  if (req.query.secret !== process.env.PREVIEW_SECRET || !req.query.slug) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  // Enable Preview Mode by setting the cookies
  res.setPreviewData({})

  // Redirect to the path from the fetched post
  res.redirect(req.query.slug)
}

3. Update your getStaticProps to use the preview client when in preview mode:

export async function getStaticProps({ preview = false, params }) {
  const activeClient = preview ? previewClient : client
  const data = await activeClient.fetch(YOUR_QUERY, params)
  
  return {
    props: { 
      data, 
      preview 
    },
    revalidate: preview ? 0 : 60 // No caching in preview mode
  }
}

4. Add an exit preview route at pages/api/exit-preview.js:

export default function handler(req, res) {
  res.clearPreviewData()
  res.redirect('/')
}

Do You Need the Studio Preview Button?

The preview button in Sanity Studio (using the Presentation tool) is helpful but not necessary. It gives editors a convenient way to jump to previews, but they can also manually visit your preview URL (like /api/preview?secret=YOUR_SECRET&slug=/blog/post-slug).

If you want to add it, you'd configure it in your Studio with the productionUrl setting, but it's purely for convenience.

About @sanity/preview-kit

The @sanity/preview-kit package you mentioned is part of the modern approach to live previews, but for basic preview mode with getStaticProps, you don't strictly need it. The setup I've shown above uses the standard Next.js preview mode with Sanity clients configured for different perspectives.

Quick Win Solution

If you just want published content to update without redeploying:

  1. Keep your revalidate value in getStaticProps (set it based on how fresh content needs to be)
  2. Set up the webhook + on-demand revalidation API route for immediate updates
  3. Configure the webhook in your Sanity project settings to call your revalidation endpoint

The time-based revalidation provides a safety net, while webhooks give you instant updates when content changes. This combination is more efficient than relying solely on time-based revalidation.

Hope this clears things up! The key insight is that ISR with on-demand revalidation via webhooks is typically the best approach for keeping content fresh without constant redeployments, and preview mode is a separate feature for viewing unpublished drafts.

Hi
user E
. Not dumb questions at all. This guide covers setting up Live Preview with Next.js, getStaticProps, and Sanity. From there, I believe you can add the
revalidate
prop to your return from getStaticProps (though not in `props`—it would be a sibling to
props
) to configure ISR .
Very sorry for the late reply
user A
I read the documents several days ago and it worked well. Thank you for the help, highly and heavily appreciated.
Not to worry! Glad that worked for you. 🙌

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?