next-cache-components

安装量: 10.6K
排名: #214

安装

npx skills add https://github.com/vercel-labs/next-skills --skill next-cache-components

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

export default function Page() { return (

Our Blog

{/ Static - instant /}
) }

  1. 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 }

  1. Dynamic (Suspense)

Runtime data that must be fresh - wrap in Suspense:

import { Suspense } from 'react'

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

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

) }

async function UserPreferences() { const theme = (await cookies()).get('theme')?.value return

Theme: {theme}

}

use cache Directive File Level 'use cache'

export default async function Page() { // Entire page is cached const data = await fetchData() return

{data}
}

Component Level export async function CachedComponent() { 'use cache' const data = await fetchData() return

{data}
}

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 APIs

cacheLife() - 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

{session}
}

// Correct - extract outside, pass as argument async function ProfilePage() { const session = (await cookies()).get('session')?.value return }

async function CachedProfile({ sessionId }: { sessionId: string }) { 'use cache' // sessionId becomes part of cache key automatically const data = await fetchUserData(sessionId) return

{data.name}
}

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 /}

Dashboard

  {/* 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 }

async function Notifications() { const userId = (await cookies()).get('userId')?.value const notifications = await db.notifications.findMany({ where: { userId, read: false } }) return }

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

import { connection } from 'next/server'

async function DynamicContent() { await connection() // Defer to request time const id = crypto.randomUUID() // Different per request return

{id}
}

Sources:

Cache Components Guide use cache Directive

返回排行榜