Skip to content
Back to skills

Next Cache Components

ASecurity

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

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentstypescriptgoreactnextjsnodeapi

Works with

  • api

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add Tekkiiiii/the-agency --skill next-cache-components --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Next Cache Components?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Next Cache Components
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tekkiiiii-next-cache-components/badge)](https://www.skillsdirectory.com/skills/tekkiiiii-next-cache-components)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Cache Components (Next.js 16+)

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

## Enable Cache Components

```typescript
// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheComponents: true,
}

export 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.

### 2. Cached (`use cache`)
Async data that doesn't need fresh fetches every request:
```typescript
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:
```typescript
import { Suspense } from 'react'

export default function Page() {
  return (
    <>
      <BlogPosts />  {/* Cached */}

      <Suspense fallback={<p>Loading...</p>}>
        <UserPreferences />  {/* Dynamic — streams in */}
      </Suspense>
    </>
  )
}
```

## use cache Directive

**File level:**
```typescript
'use cache'
export default async function Page() { /* entire page is cached */ }
```

**Component level:**
```typescript
export async function CachedComponent() {
  'use cache'
  // ...
}
```

**Function level:**
```typescript
export async function getData() {
  'use cache'
  return db.query('SELECT * FROM posts')
}
```

## Cache Profiles

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

**Custom lifetime:**
```typescript
import { cacheLife } from 'next/cache'

async function getData() {
  'use cache'
  cacheLife('hours')  // or use cacheLife({ stale: 3600, revalidate: 7200, expire: 86400 })
  return fetch('/api/data')
}
```

## Cache Invalidation

**`cacheTag()`** — tag cached content for later invalidation:
```typescript
import { cacheTag } from 'next/cache'

async function getProducts() {
  'use cache'
  cacheTag('products', `product-${id}`)
  return db.products.findMany()
}
```

**`updateTag()`** — immediate invalidation within the same request (server action):
```typescript
'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}`)  // Same request sees fresh data
}
```

**`revalidateTag()`** — background revalidation (stale-while-revalidate):
```typescript
'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:**
```typescript
// Wrong — runtime API inside use cache
async function CachedProfile() {
  'use cache'
  const session = (await cookies()).get('session')?.value  // Error!
}

// 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'
  const data = await fetchUserData(sessionId)
  return <div>{data.name}</div>
}
```

**Exception:** `'use cache: private'` allows runtime APIs for compliance requirements.

## Cache Key Generation

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

## Migration from Previous Versions

| Old | 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 |

**`unstable_cache` → `use cache` migration:**
- No manual cache keys — use cache auto-generates from arguments
- Replace `options.tags` with `cacheTag()` inside the function
- Replace `options.revalidate` with `cacheLife({ revalidate: N })` or built-in profile

## 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

For request-time randomness outside cache, use `connection()`:
```typescript
import { connection } from 'next/server'
async function DynamicContent() {
  await connection()
  const id = crypto.randomUUID()  // Different per request
  return <div>{id}</div>
}
```

---

**Source:** https://officialskills.sh/vercel-labs/skills/next-cache-components

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…