Teach Cache Components model with 'use cache' directive in Next.js 16. Use when implementing caching, optimizing performance, working with dynamic data, or migrating from Next.js 15 caching patterns.
Teaches the 'use cache' directive for Next.js 16, which flips caching from opt-out to opt-in. Use when implementing caching, optimizing performance, or migrating from Next.js 15's `unstable_cache` and route segment config.
/plugin marketplace add djankies/claude-configs/plugin install nextjs-16@claude-configsThis skill is limited to using the following tools:
references/cache-examples.mdFor understanding how caching interacts with Server Components and their rendering lifecycle, use the REACT-COMPONENTS-server-components skill from the react-19 plugin.
Next.js 16 introduces a fundamental change in how caching works:
Next.js 15 and Earlier:
dynamic = 'force-dynamic', no-store, or revalidateNext.js 16:
'use cache' directiveThis is the most significant paradigm shift in Next.js 16 and affects every application.
The 'use cache' directive is a string that tells Next.js to cache the output of a file, component, or function.
Cache an entire route or layout:
'use cache'
export default async function ProductsPage() {
const products = await db.query.products.findMany()
return <ProductList products={products} />
}
Cache a specific component:
async function ProductList() {
'use cache'
const products = await db.query.products.findMany()
return (
<div>
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
)
}
Cache the result of a function:
async function getProducts() {
'use cache'
return db.query.products.findMany()
}
export default async function ProductsPage() {
const products = await getProducts()
return <ProductList products={products} />
}
Use the 'use cache' directive when:
async function getBlogPosts() {
'use cache'
return db.query.posts.findMany({
where: { published: true },
orderBy: { publishedAt: 'desc' }
})
}
Do NOT use 'use cache' when:
export default async function UserDashboard() {
const session = await auth()
const user = await db.query.users.findFirst({
where: { id: session.userId }
})
return <Dashboard user={user} />
}
Configure cache behavior with the cacheLife and cacheTag options:
Specify how long to cache:
'use cache'
export const cacheLife = 'hours'
export default async function NewsPage() {
const articles = await fetchNews()
return <ArticleList articles={articles} />
}
Available presets:
'seconds': 1 second (real-time-ish)'minutes': 5 minutes (frequent updates)'hours': 1 hour (moderate updates)'days': 1 day (infrequent updates)'weeks': 1 week (rarely changes)'max': 1 year (effectively static)Define custom cache profiles:
'use cache'
export const cacheLife = {
stale: 60,
revalidate: 300,
expire: 3600
}
stale: Serve cached data for this many secondsrevalidate: Revalidate in background after this many secondsexpire: Hard expiration after this many secondsTag caches for on-demand revalidation:
'use cache'
export const cacheTag = 'products'
async function getProducts() {
return db.query.products.findMany()
}
Then revalidate by tag:
'use server'
import { revalidateTag } from 'next/cache'
export async function updateProduct(id: string, data: ProductInput) {
await db.update(products).set(data).where(eq(products.id, id))
revalidateTag('products')
}
Next.js 15's unstable_cache is replaced by 'use cache':
import { unstable_cache } from 'next/cache'
const getProducts = unstable_cache(
async () => {
return db.query.products.findMany()
},
['products'],
{ revalidate: 3600 }
)
async function getProducts() {
'use cache'
return db.query.products.findMany()
}
Next.js 15's route segment config doesn't work with Cache Components:
export const revalidate = 3600
export default async function Page() {
const data = await fetch('...')
return <div>{data}</div>
}
'use cache'
export const cacheLife = 'hours'
export default async function Page() {
const data = await fetch('...')
return <div>{data}</div>
}
'use cache'
export default async function Dashboard() {
const session = await auth()
const userData = await getUserData(session.userId)
return <UserDashboard data={userData} />
}
export default async function Dashboard() {
const session = await auth()
const userData = await getUserData(session.userId)
return <UserDashboard data={userData} />
}
'use cache'
export default async function Page() {
const session = await auth()
const products = await getProducts()
return (
<div>
<UserGreeting user={session.user} />
<ProductList products={products} />
</div>
)
}
async function CachedProductList() {
'use cache'
const products = await getProducts()
return <ProductList products={products} />
}
export default async function Page() {
const session = await auth()
return (
<div>
<UserGreeting user={session.user} />
<CachedProductList />
</div>
)
}
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache',
next: { revalidate: 3600 }
})
async function getData() {
'use cache'
return fetch('https://api.example.com/data')
}
const data = await getData()
export const revalidate = 3600
export const dynamic = 'force-static'
export default async function Page() {
return <div>...</div>
}
'use cache'
export const cacheLife = 'hours'
export default async function Page() {
return <div>...</div>
}
import { unstable_cache } from 'next/cache'
const getCachedPosts = unstable_cache(
async () => db.query.posts.findMany(),
['posts'],
{ revalidate: 300 }
)
async function getPosts() {
'use cache'
return db.query.posts.findMany()
}
async function getProduct(id: string) {
'use cache'
return db.query.products.findFirst({
where: eq(products.id, id)
})
}
async function getProducts() {
'use cache'
return db.query.products.findMany()
}
async function StaticProductGrid() {
'use cache'
const products = await getProducts()
return <ProductGrid products={products} />
}
export default async function Page() {
const session = await auth()
return (
<div>
<UserNav user={session?.user} />
<StaticProductGrid />
</div>
)
}
'use cache'
export const cacheTag = 'inventory'
async function getInventory() {
return db.query.inventory.findMany()
}
'use server'
import { revalidateTag } from 'next/cache'
export async function updateInventory(data: InventoryUpdate) {
await db.update(inventory).set(data)
revalidateTag('inventory')
}
For comprehensive examples and patterns, see: