Help with Next.js Cache Components: $ARGUMENTS
Auto-activates when cacheComponents: true is detected in next.config.
Next.js Cache Components
Auto-activation: This skill activates automatically in projects with
cacheComponents: truein next.config.
Project Detection
When starting work in a Next.js project, check if Cache Components are enabled:
grep -r "cacheComponents" next.config.* 2>/dev/null
If cacheComponents: true is found, apply this skill's patterns proactively when:
- Writing React Server Components
- Implementing data fetching
- Creating Server Actions with mutations
- Optimizing page performance
- Reviewing existing component code
Cache Components enable Partial Prerendering (PPR) - mixing static HTML shells with dynamic streaming content for optimal performance.
Philosophy: Code Over Configuration
| Before (Deprecated) | After (Cache Components) |
|---|---|
export const revalidate = 3600 |
cacheLife('hours') inside 'use cache' |
export const dynamic = 'force-static' |
Use 'use cache' and Suspense boundaries |
| All-or-nothing static/dynamic | Granular: static shell + cached + dynamic |
Core Concept
┌─────────────────────────────────────────────────────┐
│ Static Shell │
│ (Sent immediately to browser) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Header │ │ Cached │ │ Suspense │ │
│ │ (static) │ │ Content │ │ Fallback │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Dynamic │ │
│ │ (streams) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────┘
Quick Start
Enable Cache Components
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfig
Basic Usage
// Cached component - output included in static shell
async function CachedPosts() {
'use cache'
const posts = await db.posts.findMany()
return <PostList posts={posts} />
}
// Page with static + cached + dynamic content
export default async function BlogPage() {
return (
<>
<Header /> {/* Static */}
<CachedPosts /> {/* Cached */}
<Suspense fallback={<Skeleton />}>
<DynamicComments /> {/* Dynamic - streams */}
</Suspense>
</>
)
}
Core APIs
1. 'use cache' Directive
Marks code as cacheable. Can be applied at file, component, or function level. All cached functions must be async.
// Component-level
async function UserCard({ id }: { id: string }) {
'use cache'
const user = await fetchUser(id)
return <Card>{user.name}</Card>
}
2. cacheLife() - Control Cache Duration
import { cacheLife } from 'next/cache'
async function Posts() {
'use cache'
cacheLife('hours') // Predefined profile
// Or custom:
cacheLife({
stale: 60, // 1 min - client cache validity
revalidate: 3600, // 1 hr - background refresh
expire: 86400, // 1 day - absolute expiration
})
return await db.posts.findMany()
}
Predefined profiles: 'default', 'seconds', 'minutes', 'hours', 'days', 'weeks', 'max'
3. cacheTag() - Tag for Invalidation
import { cacheTag } from 'next/cache'
async function BlogPosts() {
'use cache'
cacheTag('posts')
cacheLife('days')
return await db.posts.findMany()
}
4. updateTag() - Immediate Invalidation
'use server'
import { updateTag } from 'next/cache'
export async function createPost(formData: FormData) {
await db.posts.create({ data: formData })
updateTag('posts') // Client immediately sees fresh data
}
5. revalidateTag() - Background Revalidation
'use server'
import { revalidateTag } from 'next/cache'
export async function updatePost(id: string, data: FormData) {
await db.posts.update({ where: { id }, data })
revalidateTag('posts', 'max') // Serve stale, refresh in background
}
When to Use Each Pattern
| Content Type | API | Behavior |
|---|---|---|
| Static | No directive | Rendered at build time |
| Cached | 'use cache' |
Included in static shell, revalidates |
| Dynamic | Inside <Suspense> |
Streams at request time |
Code Generation Guidelines
- Always use
async- All cached functions must be async - Place
'use cache'first - Must be first statement in function body - Call
cacheLife()early - Should follow'use cache'directive - Tag meaningfully - Use semantic tags that match invalidation needs
- Extract runtime data - Move
cookies()/headers()outside cached scope - Wrap dynamic content - Use
<Suspense>for non-cached async components
Code Review Checklist
- Data fetching without
'use cache'where caching would benefit - Missing
cacheTag()calls (makes invalidation impossible) - Missing
cacheLife()(relies on defaults) - Server Actions without
updateTag()/revalidateTag()after mutations -
cookies()/headers()called inside'use cache'scope - Dynamic components without
<Suspense>boundaries - DEPRECATED:
export const revalidate— replace withcacheLife() - DEPRECATED:
export const dynamic— replace with Suspense + cache boundaries
Additional Resources
- For complete API reference, see REFERENCE.md
- For common patterns and recipes, see PATTERNS.md
- For debugging and troubleshooting, see TROUBLESHOOTING.md