
Next Cache Components
Implement Next.js 16 Cache Components and Partial Prerendering so routes mix static shell, cached data, and streaming dynamic UI.
Overview
Next Cache Components is an agent skill most often used in Build (also Ship performance) that implements Next.js 16 PPR with use cache, cacheLife, cacheTag, and Suspense.
Install
npx skills add https://github.com/vercel-labs/next-skills --skill next-cache-componentsWhat is this skill?
- Enables `cacheComponents: true` in next.config.ts as the Next.js 16 replacement for experimental PPR.
- Defines three content types: static auto-prerendered shell, cached async blocks with `use cache`, and dynamic Suspense b
- Documents cacheLife presets, cacheTag, and updateTag for revalidation control.
- Shows mixing cached BlogPosts with streaming UserPreferences in one route.
- Targets Partial Prerendering: instant static regions plus deferred dynamic segments.
- Three content types: static auto-prerendered, cached use cache, and dynamic Suspense
- cacheComponents: true replaces the old experimental.ppr flag in next.config
Adoption & trust: 34k installs on skills.sh; 919 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Next.js app either over-fetches on every request or forces fully static builds that cannot stream personalized or live data.
Who is it for?
Builders on Next.js 16 App Router who want PPR without maintaining separate static and dynamic route trees.
Skip if: Pages Router-only codebases, frameworks outside Next.js, or teams that do not need incremental caching semantics.
When should I use this skill?
Working with Next.js 16 Cache Components, PPR, use cache directive, cacheLife, cacheTag, or updateTag.
What do I get? / Deliverables
You ship routes that prerender stable UI, cache shared async data with explicit lifetimes, and stream dynamic segments behind Suspense.
- next.config.ts with cacheComponents enabled
- Route implementations using use cache, cacheLife, and Suspense boundaries
- Tag-based revalidation plan with cacheTag and updateTag
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Primary shelf is Build → Frontend because the skill teaches route-level React/Next patterns (`use cache`, Suspense) during implementation. Frontend is the canonical home for PPR composition in pages and components, even though caching choices affect Ship performance.
Where it fits
Split a marketing layout into prerendered hero and cached blog list while streaming signed-in nav.
Tighten cacheLife and cacheTag rules after load testing shows stale catalog blocks.
Invalidate tagged cached modules after a pricing change without redeploying the whole site.
How it compares
Prefer this skill over legacy experimental.ppr snippets when standardizing on the cacheComponents config flag and the three-type content model.
Common Questions / FAQ
Who is next-cache-components for?
Solo developers shipping Next.js 16 sites who need clear patterns for static, cached, and dynamic regions in the same page.
When should I use next-cache-components?
While building App Router pages in Build → Frontend, and again in Ship → Perf when tuning cacheLife, tags, and streaming behavior before production traffic.
Is next-cache-components safe to install?
It is documentation and code-pattern guidance; confirm compatibility with your Next version and review the Security Audits panel on this Prism page before piping untrusted examples into CI.
SKILL.md
READMESKILL.md - 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 ```ts // 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: ```tsx export default function Page() { return ( <header> <h1>Our Blog</h1> {/* Static - instant */} <nav>...</nav> </header> ) } ``` ### 2. Cached (`use cache`) Async data that doesn't need fresh fetches every request: ```tsx 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: ```tsx import { Suspense } from 'react' export default function Page() { return ( <> <BlogPosts /> {/* Cached */} <Suspense fallback={<p>Loading...</p>}> <UserPreferences /> {/* Dynamic - streams in */} </Suspense> </> ) } async function UserPreferences() { const theme = (await cookies()).get('theme')?.value return <p>Theme: {theme}</p> } ``` --- ## `use cache` Directive ### File Level ```tsx 'use cache' export default async function Page() { // Entire page is cached const data = await fetchData() return <div>{data}</div> } ``` ### Component Level ```tsx export async function CachedComponent() { 'use cache' const data = await fetchData() return <div>{data}</div> } ``` ### Function Level ```tsx export async function getData() { 'use cache' return db.query('SELECT * FROM posts') } ``` --- ## Cache Profiles ### Built-in Profiles ```tsx 'use cache' // Default: 5m stale, 15m revalidate ``` ```tsx 'use cache: remote' // Platform-provided cache (Redis, KV) ``` ```tsx 'use cache: private' // For compliance, allows runtime APIs ``` ### `cacheLife()` - Custom Lifetime ```tsx 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 ```tsx 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 ```tsx 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: ```tsx '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: ```tsx 'use server' import { revalidateTag } from 'next/cache' export async function createPost(data: FormData) { await db.posts.create({ data }) revalidateTag('posts') // Background - next request sees f