Skill790 repo starsupdated 12d ago
cache-components
The cache-components skill provides patterns for Next.js projects with Partial Prerendering enabled, shifting from segment-level configuration to compositional code using "use cache" directives and cacheLife() within components. Use this when writing React Server Components, implementing data fetching, creating Server Actions, or optimizing performance in Next.js 15+ projects where cacheComponents is enabled in next.config.
Install in Claude Code
Copygit clone --depth 1 https://github.com/sangrokjung/claude-forge /tmp/cache-components && cp -r /tmp/cache-components/skills/cache-components ~/.claude/skills/cache-componentsThen start a new Claude Code session; the skill loads automatically.
Definition
SKILL.md
# Next.js Cache Components
> **Auto-activation**: This skill activates automatically in projects with `cacheComponents: true` in next.config.
## Project Detection
When starting work in a Next.js project, check if Cache Components are enabled:
```bash
# Check next.config.ts or next.config.js for cacheComponents
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
Cache Components represents a shift from **segment configuration** to **compositional code**:
| 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 |
**Key Principle**: Components co-locate their caching, not just their data. Next.js provides build-time feedback to guide you toward optimal patterns.
## Core Concept
```
┌─────────────────────────────────────────────────────┐
│ Static Shell │
│ (Sent immediately to browser) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Header │ │ Cached │ │ Suspense │ │
│ │ (static) │ │ Content │ │ Fallback │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Dynamic │ │
│ │ (streams) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────┘
```
## Mental Model: The Caching Decision Tree
When writing a React Server Component, ask these questions in order:
```
┌─────────────────────────────────────────────────────────┐
│ Does this component fetch data or perform I/O? │
└─────────────────────┬───────────────────────────────────┘
│
┌──────────▼──────────┐
│ YES │ NO → Pure component, no action needed
└──────────┬──────────┘
│
┌─────────────────▼─────────────────┐
│ Does it depend on request context? │
│ (cookies, headers, searchParams) │
└─────────────────┬─────────────────┘
│
┌────────────┴────────────┐
│ │
┌────▼────┐ ┌─────▼─────┐
│ YES │ │ NO │
└────┬────┘ └─────┬─────┘
│ │
│ ┌─────▼─────────────────┐
│ │ Can this be cached? │
│ │ (same for all users?) │
│ └─────┬─────────────────┘
│ │
│ ┌──────────┴──────────┐
│ │ │
│ ┌────▼────┐ ┌─────▼─────┐
│ │ YES │ │ NO │
│ └────┬────┘ └─────┬─────┘
│ │ │
│ ▼ │
│ 'use cache' │
│ + cacheTag() │
│ + cacheLife() │
│ │
└──────────────┬─────────────────────┘
│
▼
Wrap in <Suspense>
(dynamic streaming)
```
**Key insight**: The `'use cache'` directive is for data that's the _same across users_. User-specific data stays dynamic with Suspense.
## Quick Start
### Enable Cache Components
```typescript
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfig
```
### Basic Usage
```tsx
// 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 three levels:
```tsx
// File-level: All exports are cached
'use cache'
export async function getData() {
/* ... */
}
export async function Component() {
/* ... */
}
// Component-level
async function UserCard({ id }: { id: string }) {
'use cache'
const user = await fetchUser(id)
return <Card>{user.name}</Card>
}
// Function-level
async function fetchWithCache(url: string) {
'use cache'
return fetch(url).then((r) => r.json())
}
```
**Important**: All cached functions must be `async`.
### 2. `cacheLife()` - Control Cache Duration
```tsx
import { cacheLife } from 'next/cache'
async function Posts() {
'use cache'
cacheLife('hours') // Use a predefined profile
// Or custom configuration:
cacheLife({
stale: 60, // 1 min - client cache validity
revalidate: 3600, // 1 hr - start background refresh
eMore from this repository
architectSubagent
|
build-error-resolverSubagent
|
code-reviewerSubagent
|
database-reviewerSubagent
Use when writing SQL queries, creating migrations, or troubleshooting database performance in Supabase/PostgreSQL projects. Reviews indexes, RLS policies, schema types, N+1 patterns. Read-only reviewer with EXPLAIN ANALYZE capability.
doc-updaterSubagent
|
e2e-runnerSubagent
|
plannerSubagent
|
refactor-cleanerSubagent
|