
Next Cache Components
- 488 installs
- 241 repo stars
- Updated August 5, 2026
- vercel/vercel-plugin
This is a copy of next-cache-components by vercel-labs - installs and ranking accrue to the original listing.
next-cache-components is a Vercel agent skill that gives accurate guidance on Next.js 16 Cache Components—including Partial Prerendering, use cache, cacheLife, cacheTag, and updateTag—for developers implementing or migra
About
next-cache-components is a Vercel-maintained skill bundled in vercel-plugin that documents Next.js 16 caching APIs for Partial Prerendering and Cache Components workflows. It activates on next.config files, app/ and src/app/ routes, next/cache imports, and next dev or next build commands, covering use cache directives, cacheLife tuning, cacheTag labeling, updateTag invalidation, and migration away from unstable_cache. Official docs links include the Cache Components getting-started guide and use cache API reference. Developers reach for this skill when PPR routes behave unexpectedly, cache invalidation needs retagging, or legacy Next.js 14/15 cache helpers must move to the Next.js 16 model. Guidance stays aligned with Vercel platform defaults.
- Guides implementation of Partial Prerendering (PPR)
- Explains use-cache directive, cacheLife, cacheTag, and updateTag
- Provides migration path from deprecated unstable_cache
- Triggers on next dev/build commands and cache-related imports
- Includes official Next.js documentation links for cache components
Next Cache Components by the numbers
- 488 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vercel/vercel-plugin --skill next-cache-componentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 488 |
|---|---|
| repo stars | ★ 241 |
| Last updated | August 5, 2026 |
| Repository | vercel/vercel-plugin ↗ |
How do you migrate to Next.js 16 cache components?
Get accurate guidance on Next.js 16 cache components when implementing Partial Prerendering or migrating caching logic.
Who is it for?
Next.js App Router developers adopting Next.js 16 Partial Prerendering and Cache Components instead of unstable_cache.
Skip if: Pages Router-only apps, non-Next frontends, or teams not targeting Next.js 16 caching APIs.
When should I use this skill?
User implements Partial Prerendering, asks about use cache, cacheLife, cacheTag, updateTag, or unstable_cache migration.
What you get
PPR-ready route modules, cacheTag/updateTag invalidation plan, migrated cache directives
- Cache directive implementation guidance
- PPR migration checklist
By the numbers
- References 2 official Next.js documentation URLs for Cache Components and use cache
- Defines 5 path/import trigger patterns including next.config.* and app/** routes
Files
Cache Components (Next.js 16+)
Cache Components enable Partial Prerendering (PPR) - mix static, cached, and dynamic content in a single route.
Enable Cache Components
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfigThis replaces the old experimental.ppr flag.
---
Three Content Types
With Cache Components enabled, content falls into three categories:
1. Static (Auto-Prerendered)
Synchronous code, imports, pure computations - prerendered at build time:
export default function Page() {
return (
<header>
<h1>Our Blog</h1> {/* Static - instant */}
<nav>...</nav>
</header>
)
}2. Cached (use cache)
Async data that doesn't need fresh fetches every request:
async function BlogPosts() {
'use cache'
cacheLife('hours')
const posts = await db.posts.findMany()
return <PostList posts={posts} />
}3. Dynamic (Suspense)
Runtime data that must be fresh - wrap in Suspense:
import { Suspense } from 'react'
export default function Page() {
return (
<>
<BlogPosts /> {/* Cached */}
<Suspense fallback={<p>Loading...</p>}>
<UserPreferences /> {/* Dynamic - streams in */}
</Suspense>
</>
)
}
async function UserPreferences() {
const theme = (await cookies()).get('theme')?.value
return <p>Theme: {theme}</p>
}---
use cache Directive
File Level
'use cache'
export default async function Page() {
// Entire page is cached
const data = await fetchData()
return <div>{data}</div>
}Component Level
export async function CachedComponent() {
'use cache'
const data = await fetchData()
return <div>{data}</div>
}Function Level
export async function getData() {
'use cache'
return db.query('SELECT * FROM posts')
}---
Cache Profiles
Built-in Profiles
'use cache' // Default: 5m stale, 15m revalidate'use cache: remote' // Platform-provided cache (Redis, KV)'use cache: private' // For compliance, allows runtime APIscacheLife() - Custom Lifetime
import { cacheLife } from 'next/cache'
async function getData() {
'use cache'
cacheLife('hours') // Built-in profile
return fetch('/api/data')
}Built-in profiles: 'default', 'minutes', 'hours', 'days', 'weeks', 'max'
Inline Configuration
async function getData() {
'use cache'
cacheLife({
stale: 3600, // 1 hour - serve stale while revalidating
revalidate: 7200, // 2 hours - background revalidation interval
expire: 86400, // 1 day - hard expiration
})
return fetch('/api/data')
}---
Cache Invalidation
cacheTag() - Tag Cached Content
import { cacheTag } from 'next/cache'
async function getProducts() {
'use cache'
cacheTag('products')
return db.products.findMany()
}
async function getProduct(id: string) {
'use cache'
cacheTag('products', `product-${id}`)
return db.products.findUnique({ where: { id } })
}updateTag() - Immediate Invalidation
Use when you need the cache refreshed within the same request:
'use server'
import { updateTag } from 'next/cache'
export async function updateProduct(id: string, data: FormData) {
await db.products.update({ where: { id }, data })
updateTag(`product-${id}`) // Immediate - same request sees fresh data
}revalidateTag() - Background Revalidation
Use for stale-while-revalidate behavior:
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost(data: FormData) {
await db.posts.create({ data })
revalidateTag('posts') // Background - next request sees fresh data
}---
Runtime Data Constraint
Cannot access cookies(), headers(), or searchParams inside use cache.
Solution: Pass as Arguments
// Wrong - runtime API inside use cache
async function CachedProfile() {
'use cache'
const session = (await cookies()).get('session')?.value // Error!
return <div>{session}</div>
}
// Correct - extract outside, pass as argument
async function ProfilePage() {
const session = (await cookies()).get('session')?.value
return <CachedProfile sessionId={session} />
}
async function CachedProfile({ sessionId }: { sessionId: string }) {
'use cache'
// sessionId becomes part of cache key automatically
const data = await fetchUserData(sessionId)
return <div>{data.name}</div>
}Exception: use cache: private
For compliance requirements when you can't refactor:
async function getData() {
'use cache: private'
const session = (await cookies()).get('session')?.value // Allowed
return fetchData(session)
}---
Cache Key Generation
Cache keys are automatic based on:
- Build ID - invalidates all caches on deploy
- Function ID - hash of function location
- Serializable arguments - props become part of key
- Closure variables - outer scope values included
async function Component({ userId }: { userId: string }) {
const getData = async (filter: string) => {
'use cache'
// Cache key = userId (closure) + filter (argument)
return fetch(`/api/users/${userId}?filter=${filter}`)
}
return getData('active')
}---
Complete Example
import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { cacheLife, cacheTag } from 'next/cache'
export default function DashboardPage() {
return (
<>
{/* Static shell - instant from CDN */}
<header><h1>Dashboard</h1></header>
<nav>...</nav>
{/* Cached - fast, revalidates hourly */}
<Stats />
{/* Dynamic - streams in with fresh data */}
<Suspense fallback={<NotificationsSkeleton />}>
<Notifications />
</Suspense>
</>
)
}
async function Stats() {
'use cache'
cacheLife('hours')
cacheTag('dashboard-stats')
const stats = await db.stats.aggregate()
return <StatsDisplay stats={stats} />
}
async function Notifications() {
const userId = (await cookies()).get('userId')?.value
const notifications = await db.notifications.findMany({
where: { userId, read: false }
})
return <NotificationList items={notifications} />
}---
Migration from Previous Versions
| Old Config | Replacement |
|---|---|
experimental.ppr | cacheComponents: true |
dynamic = 'force-dynamic' | Remove (default behavior) |
dynamic = 'force-static' | 'use cache' + cacheLife('max') |
revalidate = N | cacheLife({ revalidate: N }) |
unstable_cache() | 'use cache' directive |
Migrating unstable_cache to use cache
unstable_cache has been replaced by the use cache directive in Next.js 16. When cacheComponents is enabled, convert unstable_cache calls to use cache functions:
Before (`unstable_cache`):
import { unstable_cache } from 'next/cache'
const getCachedUser = unstable_cache(
async (id) => getUser(id),
['my-app-user'],
{
tags: ['users'],
revalidate: 60,
}
)
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const user = await getCachedUser(id)
return <div>{user.name}</div>
}After (`use cache`):
import { cacheLife, cacheTag } from 'next/cache'
async function getCachedUser(id: string) {
'use cache'
cacheTag('users')
cacheLife({ revalidate: 60 })
return getUser(id)
}
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const user = await getCachedUser(id)
return <div>{user.name}</div>
}Key differences:
- No manual cache keys -
use cachegenerates keys automatically from function arguments and closures. ThekeyPartsarray fromunstable_cacheis no longer needed. - Tags - Replace
options.tagswithcacheTag()calls inside the function. - Revalidation - Replace
options.revalidatewithcacheLife({ revalidate: N })or a built-in profile likecacheLife('minutes'). - Dynamic data -
unstable_cachedid not supportcookies()orheaders()inside the callback. The same restriction applies touse cache, but you can use'use cache: private'if needed.
---
Limitations
- Edge runtime not supported - requires Node.js
- Static export not supported - needs server
- Non-deterministic values (
Math.random(),Date.now()) execute once at build time insideuse cache
For request-time randomness outside cache:
import { connection } from 'next/server'
async function DynamicContent() {
await connection() // Defer to request time
const id = crypto.randomUUID() // Different per request
return <div>{id}</div>
}Sources:
name: next-cache-components
description: Next.js 16 Cache Components guidance — PPR, use cache directive, cacheLife, cacheTag, updateTag, and migration from unstable_cache. Use when implementing partial prerendering, caching strategies, or migrating from older Next.js cache patterns.
metadata:
priority: 6
docs:
- "https://nextjs.org/docs/app/getting-started/cache-components"
- "https://nextjs.org/docs/app/api-reference/directives/use-cache"
pathPatterns:
- 'next.config.*'
- 'app/**'
- 'src/app/**'
- 'apps/*/app/**'
- 'apps/*/src/app/**'
importPatterns:
- "next/cache"
bashPatterns:
- '\bnext\s+(dev|build)\b'
promptSignals:
phrases:
- "use cache"
- "cache components"
- "partial prerendering"
- "PPR"
- "cacheLife"
- "cacheTag"
- "updateTag"
- "unstable_cache"
allOf:
- [cache, component]
- [cache, directive]
- [partial, prerender]
anyOf:
- "revalidateTag"
- "stale"
- "revalidate"
- "cache profile"
noneOf: []
minScore: 6
validate:
-
pattern: 'unstable_cache\s*\('
message: 'unstable_cache is deprecated in Next.js 16 — use the "use cache" directive with cacheTag() and cacheLife() instead'
severity: recommended
upgradeToSkill: next-cache-components
upgradeWhy: 'Guides migration from unstable_cache to use cache directive with cacheTag and cacheLife.'
-
pattern: '\bcacheHandler\s*:'
message: 'Singular cacheHandler is deprecated in Next.js 16 — use cacheHandlers (plural) with per-type handlers'
severity: recommended
-
pattern: revalidateTag\(\s*['"][^'"]+['"]\s*\)
message: 'Single-arg revalidateTag(tag) is deprecated in Next.js 16 — pass a cacheLife profile: revalidateTag(tag, "max")'
severity: recommended
retrieval:
aliases:
- cache components
- partial prerendering
- PPR
- use cache
intents:
- enable partial prerendering in Next.js
- cache async data with use cache directive
- invalidate cache with cacheTag
- migrate from unstable_cache
entities:
- use cache
- cacheLife
- cacheTag
- updateTag
- revalidateTag
- PPR
chainTo:
-
pattern: 'use cache'
targetSkill: nextjs
message: 'Cache component detected — loading Next.js best practices for RSC boundaries and data patterns alongside caching.'
skipIfFileContains: 'next-best-practices'
Related skills
How it compares
Prefer next-cache-components over generic Next.js skills when work specifically involves Cache Components, PPR, or unstable_cache migration on Next.js 16.
FAQ
Which Next.js 16 APIs does next-cache-components cover?
next-cache-components documents Cache Components workflows including the use cache directive, cacheLife profiles, cacheTag labeling, updateTag invalidation, and Partial Prerendering migration away from unstable_cache.
When should next-cache-components activate in a repo?
next-cache-components targets next.config files, app/ or src/app/ route modules, next/cache imports, and next dev or next build invocations—signals that a developer is editing App Router caching behavior.