Static site deployment with preview workflow for Next.js and Sanity
Great question! This is a common setup for Sanity + Next.js sites, and there are several proven approaches to handle static production deployments with dynamic previews. Here's how people typically handle this workflow:
The Standard Setup
Production (Static on S3): Use Next.js Static Export (output: 'export') to generate a fully static site that you deploy to S3/CloudFront. This queries Sanity's published content.
Preview Site (Dynamic): Host a separate Next.js instance (on Vercel, Netlify, or any Node.js host) that runs in dynamic mode and uses Next.js Draft Mode to show unpublished drafts from Sanity.
Triggering Production Rebuilds
You have a few solid options for controlling when your static site gets rebuilt:
Option 1: Webhooks (Most Common)
Set up a Sanity webhook that triggers your build pipeline when content changes. Webhooks are GROQ-powered, so you can filter them to only fire on published documents (not drafts) using filters like !(_id in path("drafts.**")). This gives you precise control over when production updates happen.
Your webhook can call your CI/CD pipeline (GitHub Actions, AWS CodeBuild, etc.) to rebuild and deploy to S3. You can also customize the webhook payload using GROQ projections to include exactly the data your build process needs.
Option 2: Sanity Functions
Sanity Functions are serverless functions that run on Sanity's infrastructure and can react to document events. They're currently an experimental feature with APIs subject to change, but they offer a way to trigger your deployment pipeline without hosting your own webhook endpoint.
Functions can listen for document publish events and call your CI/CD API to kick off a rebuild. The main advantage is that everything stays within your Sanity project, but be aware this feature is still evolving.
Option 3: Manual Deploys
For smaller teams or less frequently updated content, you might just trigger builds manually through your CI/CD dashboard when ready to publish. Simple and reliable!
The Preview Workflow
For the preview site, set up an API route that enables Draft Mode:
// app/api/draft/route.ts
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const secret = searchParams.get('secret')
const slug = searchParams.get('slug')
// Validate secret token
if (secret !== process.env.SANITY_PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 })
}
draftMode().enable()
redirect(slug || '/')
}Then in your data fetching, use Sanity's perspective API to fetch drafts when in preview mode:
const client = createClient({
// ...config
perspective: draftMode().isEnabled ? 'previewDrafts' : 'published',
useCdn: !draftMode().isEnabled
})You can add a "Preview" button in Sanity Studio that links editors to your preview site with the draft mode URL, making it seamless for content creators to see their changes before publishing.
Alternative: ISR Instead of Full Static
If you're open to hosting your production site somewhere that supports server-side features (not pure S3), consider using Incremental Static Regeneration (ISR) instead. This lets you:
- Keep pages static for performance
- Use time-based or on-demand revalidation to update content without full rebuilds
- Still use Draft Mode for previews
With ISR, you'd use revalidateTag() or revalidatePath() in an API route triggered by Sanity webhooks for instant updates when content changes. This eliminates the wait time for full rebuilds while keeping most of the benefits of static generation.
The Bottom Line
Your S3 static export approach is totally valid—especially if you want zero server costs and maximum simplicity. The most common pattern is:
- Webhooks to trigger rebuilds when content is published (filtered to only published docs)
- Draft Mode on a separate preview environment for editors to see changes before publishing
- A simple "Preview" link in Studio that opens the preview site
This gives you full control over the production deployment timing while keeping the preview experience smooth for your content team!
Show original thread3 replies
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.