KS
Killer-Skills

next-cache-components — how to use next-cache-components how to use next-cache-components, what is next-cache-components, next-cache-components alternative, next-cache-components vs react, next-cache-components install, next-cache-components setup guide, next.js 16+ cache components, partial prerendering next.js

Verified
v1.0.0
GitHub

About this Skill

Perfect for Next.js Agents needing advanced caching and prerendering capabilities for mixed static, cached, and dynamic content. next-cache-components is a Next.js feature that enables Partial Prerendering (PPR), allowing for mixed content types in a single route.

Features

Enables Partial Prerendering (PPR) in Next.js 16+
Supports mixed static, cached, and dynamic content in a single route
Replaces the old `experimental.ppr` flag
Configurable via `next.config.ts` file
Allows for three content types: static, cached, and dynamic

# Core Topics

vercel-labs vercel-labs
[0]
[0]
Updated: 3/7/2026

Quality Score

Top 5%
33
Excellent
Based on code quality & docs
Installation
SYS Universal Install (Auto-Detect)
Cursor IDE Windsurf IDE VS Code IDE
> npx killer-skills add vercel-labs/next-skills/next-cache-components

Agent Capability Analysis

The next-cache-components MCP Server by vercel-labs is an open-source Categories.community integration for Claude and other AI agents, enabling seamless task automation and capability expansion. Optimized for how to use next-cache-components, what is next-cache-components, next-cache-components alternative.

Ideal Agent Persona

Perfect for Next.js Agents needing advanced caching and prerendering capabilities for mixed static, cached, and dynamic content.

Core Value

Empowers agents to leverage Partial Prerendering (PPR) in Next.js 16+, seamlessly integrating static, cached, and dynamic content in a single route using cacheComponents in next.config.ts.

Capabilities Granted for next-cache-components MCP Server

Enabling Partial Prerendering for improved performance
Mixing static and dynamic content in a single Next.js route
Optimizing Next.js applications with cacheComponents

! Prerequisites & Limits

  • Requires Next.js 16+
  • Needs cacheComponents flag enabled in next.config.ts
Project
SKILL.md
9.0 KB
.cursorrules
1.2 KB
package.json
240 B
Ready
UTF-8

# Tags

[No tags]
SKILL.md
Readonly

Cache Components (Next.js 16+)

Cache Components enable Partial Prerendering (PPR) - mix static, cached, and dynamic content in a single route.

Enable Cache Components

ts
1// next.config.ts 2import type { NextConfig } from 'next' 3 4const nextConfig: NextConfig = { 5 cacheComponents: true, 6} 7 8export default nextConfig

This 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:

tsx
1export default function Page() { 2 return ( 3 <header> 4 <h1>Our Blog</h1> {/* Static - instant */} 5 <nav>...</nav> 6 </header> 7 ) 8}

2. Cached (use cache)

Async data that doesn't need fresh fetches every request:

tsx
1async function BlogPosts() { 2 'use cache' 3 cacheLife('hours') 4 5 const posts = await db.posts.findMany() 6 return <PostList posts={posts} /> 7}

3. Dynamic (Suspense)

Runtime data that must be fresh - wrap in Suspense:

tsx
1import { Suspense } from 'react' 2 3export default function Page() { 4 return ( 5 <> 6 <BlogPosts /> {/* Cached */} 7 8 <Suspense fallback={<p>Loading...</p>}> 9 <UserPreferences /> {/* Dynamic - streams in */} 10 </Suspense> 11 </> 12 ) 13} 14 15async function UserPreferences() { 16 const theme = (await cookies()).get('theme')?.value 17 return <p>Theme: {theme}</p> 18}

use cache Directive

File Level

tsx
1'use cache' 2 3export default async function Page() { 4 // Entire page is cached 5 const data = await fetchData() 6 return <div>{data}</div> 7}

Component Level

tsx
1export async function CachedComponent() { 2 'use cache' 3 const data = await fetchData() 4 return <div>{data}</div> 5}

Function Level

tsx
1export async function getData() { 2 'use cache' 3 return db.query('SELECT * FROM posts') 4}

Cache Profiles

Built-in Profiles

tsx
1'use cache' // Default: 5m stale, 15m revalidate
tsx
1'use cache: remote' // Platform-provided cache (Redis, KV)
tsx
1'use cache: private' // For compliance, allows runtime APIs

cacheLife() - Custom Lifetime

tsx
1import { cacheLife } from 'next/cache' 2 3async function getData() { 4 'use cache' 5 cacheLife('hours') // Built-in profile 6 return fetch('/api/data') 7}

Built-in profiles: 'default', 'minutes', 'hours', 'days', 'weeks', 'max'

Inline Configuration

tsx
1async function getData() { 2 'use cache' 3 cacheLife({ 4 stale: 3600, // 1 hour - serve stale while revalidating 5 revalidate: 7200, // 2 hours - background revalidation interval 6 expire: 86400, // 1 day - hard expiration 7 }) 8 return fetch('/api/data') 9}

Cache Invalidation

cacheTag() - Tag Cached Content

tsx
1import { cacheTag } from 'next/cache' 2 3async function getProducts() { 4 'use cache' 5 cacheTag('products') 6 return db.products.findMany() 7} 8 9async function getProduct(id: string) { 10 'use cache' 11 cacheTag('products', `product-${id}`) 12 return db.products.findUnique({ where: { id } }) 13}

updateTag() - Immediate Invalidation

Use when you need the cache refreshed within the same request:

tsx
1'use server' 2 3import { updateTag } from 'next/cache' 4 5export async function updateProduct(id: string, data: FormData) { 6 await db.products.update({ where: { id }, data }) 7 updateTag(`product-${id}`) // Immediate - same request sees fresh data 8}

revalidateTag() - Background Revalidation

Use for stale-while-revalidate behavior:

tsx
1'use server' 2 3import { revalidateTag } from 'next/cache' 4 5export async function createPost(data: FormData) { 6 await db.posts.create({ data }) 7 revalidateTag('posts') // Background - next request sees fresh data 8}

Runtime Data Constraint

Cannot access cookies(), headers(), or searchParams inside use cache.

Solution: Pass as Arguments

tsx
1// Wrong - runtime API inside use cache 2async function CachedProfile() { 3 'use cache' 4 const session = (await cookies()).get('session')?.value // Error! 5 return <div>{session}</div> 6} 7 8// Correct - extract outside, pass as argument 9async function ProfilePage() { 10 const session = (await cookies()).get('session')?.value 11 return <CachedProfile sessionId={session} /> 12} 13 14async function CachedProfile({ sessionId }: { sessionId: string }) { 15 'use cache' 16 // sessionId becomes part of cache key automatically 17 const data = await fetchUserData(sessionId) 18 return <div>{data.name}</div> 19}

Exception: use cache: private

For compliance requirements when you can't refactor:

tsx
1async function getData() { 2 'use cache: private' 3 const session = (await cookies()).get('session')?.value // Allowed 4 return fetchData(session) 5}

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
tsx
1async function Component({ userId }: { userId: string }) { 2 const getData = async (filter: string) => { 3 'use cache' 4 // Cache key = userId (closure) + filter (argument) 5 return fetch(`/api/users/${userId}?filter=${filter}`) 6 } 7 return getData('active') 8}

Complete Example

tsx
1import { Suspense } from 'react' 2import { cookies } from 'next/headers' 3import { cacheLife, cacheTag } from 'next/cache' 4 5export default function DashboardPage() { 6 return ( 7 <> 8 {/* Static shell - instant from CDN */} 9 <header><h1>Dashboard</h1></header> 10 <nav>...</nav> 11 12 {/* Cached - fast, revalidates hourly */} 13 <Stats /> 14 15 {/* Dynamic - streams in with fresh data */} 16 <Suspense fallback={<NotificationsSkeleton />}> 17 <Notifications /> 18 </Suspense> 19 </> 20 ) 21} 22 23async function Stats() { 24 'use cache' 25 cacheLife('hours') 26 cacheTag('dashboard-stats') 27 28 const stats = await db.stats.aggregate() 29 return <StatsDisplay stats={stats} /> 30} 31 32async function Notifications() { 33 const userId = (await cookies()).get('userId')?.value 34 const notifications = await db.notifications.findMany({ 35 where: { userId, read: false } 36 }) 37 return <NotificationList items={notifications} /> 38}

Migration from Previous Versions

Old ConfigReplacement
experimental.pprcacheComponents: true
dynamic = 'force-dynamic'Remove (default behavior)
dynamic = 'force-static''use cache' + cacheLife('max')
revalidate = NcacheLife({ 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):

tsx
1import { unstable_cache } from 'next/cache' 2 3const getCachedUser = unstable_cache( 4 async (id) => getUser(id), 5 ['my-app-user'], 6 { 7 tags: ['users'], 8 revalidate: 60, 9 } 10) 11 12export default async function Page({ params }: { params: Promise<{ id: string }> }) { 13 const { id } = await params 14 const user = await getCachedUser(id) 15 return <div>{user.name}</div> 16}

After (use cache):

tsx
1import { cacheLife, cacheTag } from 'next/cache' 2 3async function getCachedUser(id: string) { 4 'use cache' 5 cacheTag('users') 6 cacheLife({ revalidate: 60 }) 7 return getUser(id) 8} 9 10export default async function Page({ params }: { params: Promise<{ id: string }> }) { 11 const { id } = await params 12 const user = await getCachedUser(id) 13 return <div>{user.name}</div> 14}

Key differences:

  • No manual cache keys - use cache generates keys automatically from function arguments and closures. The keyParts array from unstable_cache is no longer needed.
  • Tags - Replace options.tags with cacheTag() calls inside the function.
  • Revalidation - Replace options.revalidate with cacheLife({ revalidate: N }) or a built-in profile like cacheLife('minutes').
  • Dynamic data - unstable_cache did not support cookies() or headers() inside the callback. The same restriction applies to use 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 inside use cache

For request-time randomness outside cache:

tsx
1import { connection } from 'next/server' 2 3async function DynamicContent() { 4 await connection() // Defer to request time 5 const id = crypto.randomUUID() // Different per request 6 return <div>{id}</div> 7}

Sources:

Related Skills

Looking for an alternative to next-cache-components or building a Categories.community AI Agent? Explore these related open-source MCP Servers.

View All

widget-generator

Logo of f
f

widget-generator is an open-source AI agent skill for creating widget plugins that are injected into prompt feeds on prompts.chat. It supports two rendering modes: standard prompt widgets using default PromptCard styling and custom render widgets built as full React components.

149.6k
0
Design

chat-sdk

Logo of lobehub
lobehub

chat-sdk is a unified TypeScript SDK for building chat bots across multiple platforms, providing a single interface for deploying bot logic.

73.0k
0
Communication

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication