Install
$ agentstack add skill-t-code4change-nextjs-claude-skills-nextjs-caching ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Next.js Caching (Cache Components)
> Requires: cacheComponents: true in next.config.ts (Next.js 16).
Project Detection
grep -r "cacheComponents" next.config.* 2>/dev/null
Enable
// next.config.ts
const nextConfig: NextConfig = { cacheComponents: true };
export default nextConfig;
Decision Steps
- Does component fetch data? No → skip. Yes → continue.
- Depends on
cookies()/headers()/searchParams? No → step 3. Yes → step 4. - Same data for all users? Yes →
'use cache'+cacheTag()+cacheLife(). No → ``. - Can extract runtime data as args? Yes → pass outside cache. No →
'use cache: private'(last resort).
Core APIs
'use cache' Directive
async function BlogPosts() {
'use cache'; // MUST be first statement; function MUST be async
cacheTag('posts');
cacheLife('hours');
return await db.posts.findMany();
}
cacheLife() Profiles
cacheLife('seconds'); // stale:30s | revalidate:1s | expire:1m
cacheLife('minutes'); // stale:5m | revalidate:1m | expire:1h
cacheLife('hours'); // stale:5m | revalidate:1h | expire:1d
cacheLife('days'); // stale:5m | revalidate:1d | expire:1w
cacheLife('weeks'); // stale:5m | revalidate:1w | expire:30d
cacheLife('max'); // stale:5m | revalidate:30d | expire:1y
// Custom:
cacheLife({ stale: 60, revalidate: 3600, expire: 86400 });
By content type: news → seconds, blog/docs → hours, marketing → days, legal → max
cacheTag() + Invalidation
// Tag
async function ProductList({ category }: { category: string }) {
'use cache';
cacheTag('products', `category-${category}`);
cacheLife('hours');
return await db.products.findMany({ where: { category } });
}
// Invalidate — Server Action (immediate, read-your-own-writes)
'use server';
export async function createProduct(formData: FormData): Promise {
await db.products.create({ data: parseFormData(formData) });
updateTag('products');
}
// Invalidate — Route Handler / webhook (stale-while-revalidate)
export async function POST(request: Request) {
const { tag } = await request.json();
revalidateTag(tag, 'max'); // two-arg form — single arg is DEPRECATED
return Response.json({ revalidated: true });
}
Server Actions vs Data Fetching (CRITICAL)
// ❌ WRONG: Server Action for data fetch
'use server';
export async function getProducts() { return await db.products.findMany(); }
// ✅ CORRECT: cached data function
export async function getProducts() {
'use cache';
cacheTag('products');
cacheLife('hours');
return await db.products.findMany();
}
// ✅ CORRECT: Server Action for mutation only
'use server';
export async function createProduct(formData: FormData): Promise {
await db.products.create({ data: formData });
updateTag('products');
}
PPR Pattern
export default async function ProductPage({ params }) {
const { id } = await params;
return (
<>
{/* static */}
{/* 'use cache' — in static shell */}
}>
{/* dynamic — streams after load */}
);
}
async function CachedProductDetails({ id }: { id: string }) {
'use cache';
cacheTag(`product-${id}`);
cacheLife('hours');
const product = await db.products.findUnique({ where: { id } });
return ;
}
Runtime Data Pattern (cookies inside cache)
// ❌ WRONG: cookies() inside 'use cache'
async function UserData() {
'use cache';
const cookieStore = await cookies(); // ERROR
}
// ✅ CORRECT: extract outside, pass as arg
async function UserDataWrapper() {
const cookieStore = await cookies();
const userId = cookieStore.get('userId')?.value;
return ;
}
async function CachedUserData({ userId }: { userId: string }) {
'use cache';
cacheTag(`user-${userId}`);
cacheLife('minutes');
return await getUser(userId);
}
Review Checklist
- [ ]
cacheComponents: trueinnext.config.ts - [ ] All
'use cache'functions areasync - [ ]
'use cache'is first statement - [ ]
cacheTag()present (enables targeted invalidation) - [ ]
cacheLife()present (don't rely on defaults) - [ ]
cookies()/headers()NOT inside'use cache'scope - [ ] Server Actions call
updateTag()after mutations - [ ] Dynamic components wrapped in ``
- [ ]
revalidateTag(tag, profile)— two-arg form (not deprecated single-arg) - [ ] Server Actions return
void, never used for data fetching
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: t-code4change
- Source: t-code4change/nextjs-claude-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.