Ensure accessibility in UI components including semantic HTML, ARIA attributes, keyboard navigation, and WCAG 2.2 AA compliance.
日本語の概要は準備中です。原文の説明を表示しています。
Next.js 16 caching model expertise covering the 'use cache' directive, cacheLife() API, cacheTag() for invalidation, cacheComponents configuration, and Partial Prerendering (PPR). Use when implementing caching strategies in Next.js 16+ applications, migrating from unstable_cache, or optimizing server component rendering.
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Deep expertise on the Next.js 16 caching model. Covers the 'use cache' directive, cacheLife() profiles, cacheTag() invalidation, cacheComponents configuration, and Partial Prerendering (PPR) integration.
Use this skill when:
unstable_cache or revalidate patterns to the new caching APIcacheComponentsNext.js 16 introduces a fundamentally new caching model:
| Feature | Next.js 14 | Next.js 15 | Next.js 16 |
|---|---|---|---|
| fetch() caching | Cached by default | Not cached by default | Not cached by default |
| Route caching | Automatic | Opt-in | 'use cache' directive |
| Data caching | revalidate option | revalidate option | cacheLife() API |
| Invalidation | revalidateTag() | revalidateTag() | cacheTag() + revalidateTag() |
| Component caching | Not available | Experimental | cacheComponents: true |
In Next.js 16, caching is explicit and opt-in. Nothing is cached unless you explicitly use the 'use cache' directive.
Add 'use cache' at the top of a file or function to enable caching:
// app/page.tsx -- cache the entire page
'use cache';
export default async function Page() {
const data = await fetch('https://api.example.com/data');
const posts = await data.json();
return (
<main>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.body}</p>
</article>
))}
</main>
);
}
Cache individual async functions instead of entire pages:
// lib/data.ts
import { cacheLife, cacheTag } from 'next/cache';
export async function getUser(id: string) {
'use cache';
cacheLife('hours');
cacheTag(`user-${id}`);
const res = await fetch(`https://api.example.com/users/${id}`);
return res.json();
}
export async function getPosts() {
'use cache';
cacheLife('minutes');
cacheTag('posts');
const res = await fetch('https://api.example.com/posts');
return res.json();
}
With cacheComponents: true in next.config.ts, individual Server Components can be cached:
// next.config.ts
const nextConfig = {
cacheComponents: true,
};
export default nextConfig;
// components/user-profile.tsx
import { cacheLife, cacheTag } from 'next/cache';
export async function UserProfile({ userId }: { userId: string }) {
'use cache';
cacheLife('hours');
cacheTag(`user-profile-${userId}`);
const user = await fetch(`/api/users/${userId}`).then(r => r.json());
return (
<div className="profile-card">
<img src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
);
}
Key benefit: The page can re-render while the cached component serves from cache, avoiding redundant data fetches for unchanged components.
import { cacheLife } from 'next/cache';
// Predefined profiles
cacheLife('seconds'); // stale: 0, revalidate: 1s, expire: 60s
cacheLife('minutes'); // stale: 5min, revalidate: 1min, expire: 1h
cacheLife('hours'); // stale: 5min, revalidate: 1h, expire: 1d
cacheLife('days'); // stale: 5min, revalidate: 1d, expire: 1w
cacheLife('weeks'); // stale: 5min, revalidate: 1w, expire: 30d
cacheLife('max'); // stale: 5min, revalidate: 30d, expire: 365d
Define custom cache profiles in next.config.ts:
// next.config.ts
const nextConfig = {
cacheLife: {
'blog-post': {
stale: 300, // 5 minutes -- serve stale while revalidating
revalidate: 3600, // 1 hour -- revalidate in background
expire: 86400, // 1 day -- maximum cache lifetime
},
'user-session': {
stale: 0, // Never serve stale
revalidate: 60, // Revalidate every minute
expire: 300, // Expire after 5 minutes
},
'static-content': {
stale: 3600, // 1 hour stale tolerance
revalidate: 86400, // Revalidate daily
expire: 604800, // Expire after 1 week
},
},
};
Usage:
async function getBlogPost(slug: string) {
'use cache';
cacheLife('blog-post');
cacheTag(`blog-${slug}`);
return fetch(`/api/posts/${slug}`).then(r => r.json());
}
| Content Type | Profile | Rationale |
|---|---|---|
| Static pages | 'max' or 'weeks' | Content rarely changes |
| Blog posts | 'days' or custom | Updated occasionally |
| Product listings | 'hours' | Prices/stock change moderately |
| User dashboards | 'minutes' | Data updates frequently |
| Real-time feeds | 'seconds' or no cache | Data changes constantly |
| Auth-dependent | custom (stale: 0) | Must never serve stale auth data |
import { cacheTag } from 'next/cache';
async function getProduct(id: string) {
'use cache';
cacheLife('hours');
cacheTag('products', `product-${id}`);
return fetch(`/api/products/${id}`).then(r => r.json());
}
Use revalidateTag() in Server Actions or Route Handlers:
// app/actions.ts
'use server';
import { revalidateTag } from 'next/cache';
export async function updateProduct(id: string, data: ProductData) {
await db.products.update(id, data);
// Invalidate specific product cache
revalidateTag(`product-${id}`);
// Invalidate all products listing
revalidateTag('products');
}
entity-type -> 'products', 'users', 'posts'
entity-type-id -> 'product-123', 'user-456'
entity-type-relation -> 'product-reviews', 'user-orders'
entity-type-relation-id -> 'product-123-reviews'
// Tag hierarchy for a blog
cacheTag('blog'); // All blog content
cacheTag('blog', `blog-${slug}`); // Specific post
cacheTag('blog', 'blog-comments'); // All comments
cacheTag('blog', `blog-comments-${postId}`); // Post comments
// Invalidate all blog content
revalidateTag('blog');
// Invalidate just one post
revalidateTag(`blog-${slug}`);
PPR combines static shells with dynamic holes, and 'use cache' works with it.
// app/product/[id]/page.tsx
import { Suspense } from 'react';
import { ProductDetails } from './product-details';
import { RecommendedProducts } from './recommended';
import { UserReviews } from './reviews';
// Static shell (prerendered at build time)
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
return (
<main>
{/* Cached component -- serves from cache */}
<ProductDetails productId={id} />
{/* Dynamic holes -- rendered on request */}
<Suspense fallback={<ReviewsSkeleton />}>
<UserReviews productId={id} />
</Suspense>
<Suspense fallback={<RecommendedSkeleton />}>
<RecommendedProducts productId={id} />
</Suspense>
</main>
);
}
// components/product-details.tsx
import { cacheLife, cacheTag } from 'next/cache';
export async function ProductDetails({ productId }: { productId: string }) {
'use cache';
cacheLife('hours');
cacheTag(`product-${productId}`);
const product = await fetch(`/api/products/${productId}`).then(r => r.json());
return (
<section>
<h1>{product.name}</h1>
<p>{product.description}</p>
<span>${product.price}</span>
</section>
);
}
// next.config.ts
const nextConfig = {
ppr: true, // Enable Partial Prerendering
cacheComponents: true, // Enable component-level caching
};
// Before (Next.js 14/15)
import { unstable_cache } from 'next/cache';
const getCachedUser = unstable_cache(
async (id: string) => {
return db.users.findUnique({ where: { id } });
},
['user'],
{ revalidate: 3600, tags: ['users'] }
);
// After (Next.js 16)
import { cacheLife, cacheTag } from 'next/cache';
async function getUser(id: string) {
'use cache';
cacheLife('hours');
cacheTag('users', `user-${id}`);
return db.users.findUnique({ where: { id } });
}
// Before (Next.js 14)
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 3600, tags: ['data'] },
});
// After (Next.js 16)
async function getData() {
'use cache';
cacheLife('hours');
cacheTag('data');
return fetch('https://api.example.com/data').then(r => r.json());
}
// Before (Next.js 14/15)
export const revalidate = 3600;
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map(post => ({ slug: post.slug }));
}
// After (Next.js 16) -- use 'use cache' at page level
('use cache');
import { cacheLife } from 'next/cache';
cacheLife('hours');
export default async function Page({ params }) {
const { slug } = await params;
// ...
}
Create a centralized data access layer with caching:
// lib/data/products.ts
import { cacheLife, cacheTag } from 'next/cache';
export async function getProduct(id: string) {
'use cache';
cacheLife('hours');
cacheTag('products', `product-${id}`);
return prisma.product.findUnique({ where: { id } });
}
export async function getProducts(category?: string) {
'use cache';
cacheLife('minutes');
cacheTag('products', category ? `category-${category}` : 'all-products');
return prisma.product.findMany({
where: category ? { category } : undefined,
orderBy: { createdAt: 'desc' },
});
}
Cache public data but keep auth-dependent data dynamic:
// Cached: product data (same for all users)
async function ProductInfo({ id }: { id: string }) {
'use cache';
cacheLife('hours');
cacheTag(`product-${id}`);
const product = await getProduct(id);
return <ProductCard product={product} />;
}
// NOT cached: user-specific data
async function UserCartStatus({ userId }: { userId: string }) {
// No 'use cache' -- always dynamic
const cart = await getCart(userId);
return <CartBadge count={cart.items.length} />;
}
'use cache' explicitly on every component or function you intend to cache — in Next.js 16, nothing is cached unless you opt in; implicit caching assumptions from Next.js 14 are gone.'use cache' on components that render user-specific or auth-dependent data — the cache key does not include session context; different users will receive each other's cached content.cacheTag() on every cached function that reads mutable data — without tags, there is no way to invalidate stale data after a mutation; the only recourse is waiting for expiry.'use cache' returns a cached response instead of executing the mutation; data changes are silently discarded.revalidateTag() in Server Actions or Route Handlers immediately after a mutation — forgetting invalidation means stale data persists for the full cache lifetime after every write.| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
Using 'use cache' on auth-dependent components | Cache key excludes session context; different users receive each other's cached data | Keep auth-dependent components dynamic; cache only public, user-agnostic data |
| Caching Server Actions that mutate data | Returns cached response instead of executing mutation; writes are silently discarded | Never put 'use cache' on mutation actions; only cache read operations |
Missing cacheTag() on mutable data | No invalidation path; stale data persists until expiry with no way to purge on mutation | Always tag cached data: cacheTag('entity', 'entity-id') |
Forgetting revalidateTag() after mutations | Stale data persists for full cache lifetime after every write | Call revalidateTag() in every Server Action or Route Handler that modifies data |
| Overly broad cache tag names | revalidateTag('all') invalidates the entire cache on every mutation — defeats purpose | Use granular hierarchical tags: 'products', 'product-{id}' |
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Ensure accessibility in UI components including semantic HTML, ARIA attributes, keyboard navigation, and WCAG 2.2 AA compliance.
日本語の概要は準備中です。原文の説明を表示しています。
Use when you want to improve response quality through meta-cognitive reasoning. Applies 15+ reasoning methods to reconsider and refine initial outputs.
日本語の概要は準備中です。原文の説明を表示しています。
N-round opposing-stance debates for trade-off analysis. Assigns pro/con roles to agents, runs structured debate rounds with quality scoring, and produces a moderator synthesis with confidence-rated recommendation. Generalizable to architecture, technology, security, and design decisions.
日本語の概要は準備中です。原文の説明を表示しています。
Force adversarial code review stance that eliminates confirmation bias — reviewer must find issues or re-analyze
日本語の概要は準備中です。原文の説明を表示しています。
Creates specialized AI agents on-demand when no existing agent matches a request. Use when the Router cannot find a suitable agent for a task. Enables self-evolution by generating persistent agents.
日本語の概要は準備中です。原文の説明を表示しています。
LLM-as-judge evaluation framework with 5-dimension rubric (accuracy, groundedness, coherence, completeness, helpfulness) for scoring AI-generated content quality with weighted composite scores and evidence citations
日本語の概要は準備中です。原文の説明を表示しています。