
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeYou're right that the documentation has changed! Next.js App Router (introduced in Next.js 13+) completely replaced the need for getStaticProps and getServerSideProps with a simpler, more powerful approach using React Server Components. Many people are successfully using Sanity with Next.js—it's actually one of the most popular stacks for content-driven applications.
With the App Router (the app/ directory), you fetch data directly inside your components. No special functions needed! Here's how it works:
// app/blog/page.tsx
import { createClient } from 'next-sanity'
const client = createClient({
projectId: 'your-project-id',
dataset: 'production',
apiVersion: '2024-01-01',
useCdn: true,
})
// Control caching behavior
export const revalidate = 60 // Revalidate every 60 seconds
export default async function BlogPage() {
// Fetch data directly in the component
const posts = await client.fetch(`*[_type == "post"]`)
return (
<div>
{posts.map(post => (
<article key={post._id}>{post.title}</article>
))}
</div>
)
}npm install next-sanity @sanity/image-urllib/sanity.ts):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, // Use CDN for faster reads in production
})The App Router gives you several ways to control caching, replacing the old getStaticProps/getServerSideProps patterns:
Time-based revalidation (like ISR):
export const revalidate = 3600 // Revalidate every hourForce dynamic rendering (like getServerSideProps):
export const dynamic = 'force-dynamic'No caching for specific fetches:
const posts = await client.fetch(query, {}, { cache: 'no-store' })For dynamic routes, use generateStaticParams instead of getStaticPaths:
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await client.fetch(`*[_type == "post"]{ "slug": slug.current }`)
return posts.map((post) => ({
slug: post.slug,
}))
}
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await client.fetch(
`*[_type == "post" && slug.current == $slug][0]`,
{ slug: params.slug }
)
return <article>{post.title}</article>
}If you're using Next.js 15, params are now a Promise, so you need to await them:
export default async function BlogPost({
params
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params // Must await!
const post = await client.fetch(...)
return <article>{post.title}</article>
}The next-sanity toolkit provides everything you need for building production-grade Next.js applications with Sanity, including utilities for live content updates and visual editing. There's also a comprehensive App Router course that walks through fetching Sanity content step-by-step.
The pattern is actually simpler once you understand that components themselves are async and can fetch data directly—no need for the old data-fetching functions!
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store