cache-components
About
This skill helps developers implement Next.js 16 Cache Components to optimize page performance. It assists with adding "use cache" directives, setting up Suspense boundaries, and configuring cacheLife profiles. Use it when migrating components to cache mode or debugging cache-related issues.
Documentation
Next.js Cache Components Skill
This skill helps you implement and optimize Next.js 16 Cache Components in apps/web/.
When to Use This Skill
- Converting components to use Cache Components
- Adding "use cache" directives to functions
- Implementing Suspense boundaries
- Configuring cacheLife profiles
- Debugging cache-related errors
- Optimizing page load performance
Cache Components Overview
Next.js 16 introduced Cache Components to improve performance by caching component render results.
Key Concepts
- "use cache" directive: Marks functions/components for caching
- Suspense boundaries: Required for streaming cached content
- cacheLife profiles: Control cache duration and invalidation
- cacheTag: Manual cache invalidation
- Dynamic vs Static: Understanding when caching applies
Implementation Patterns
1. Basic Cache Component
// app/components/car-list.tsx
import { Suspense } from "react";
async function CarList() {
"use cache";
const cars = await db.query.cars.findMany();
return (
<div>
{cars.map(car => (
<div key={car.id}>{car.make} {car.model}</div>
))}
</div>
);
}
// Parent component with Suspense
export default function CarsPage() {
return (
<Suspense fallback={<div>Loading cars...</div>}>
<CarList />
</Suspense>
);
}
2. Cache with cacheLife
Control cache duration:
import { cacheLife } from "next/cache";
async function COEData() {
"use cache";
cacheLife("hours"); // Built-in profile: cache for hours
const coe = await db.query.coe.findMany();
return <COETable data={coe} />;
}
// Custom cache profile
async function RealtimeData() {
"use cache";
cacheLife({
stale: 60, // Serve stale for 60 seconds
revalidate: 300, // Revalidate after 5 minutes
expire: 3600, // Expire after 1 hour
});
const data = await fetchRealtimeData();
return <DataDisplay data={data} />;
}
3. Cache Tags for Invalidation
import { cacheTag } from "next/cache";
async function BlogPosts() {
"use cache";
cacheTag("blog-posts"); // Tag for manual invalidation
const posts = await db.query.posts.findMany();
return <PostList posts={posts} />;
}
// Invalidate cache in server action
"use server";
import { revalidateTag } from "next/cache";
export async function createPost(data: PostData) {
await db.insert(posts).values(data);
revalidateTag("blog-posts"); // Invalidate cached blog posts
}
4. Private Cache (User-Specific)
import { cookies } from "next/headers";
async function UserDashboard() {
"use cache: private"; // Cache per-user, not globally
const cookieStore = await cookies();
const userId = cookieStore.get("userId")?.value;
const userData = await fetchUserData(userId);
return <Dashboard data={userData} />;
}
5. Nested Cache Components
// Outer component - longer cache
async function CarsByMake({ make }: { make: string }) {
"use cache";
cacheLife("days");
const cars = await db.query.cars.findMany({
where: eq(cars.make, make),
});
return (
<div>
<h2>{make} Models</h2>
<Suspense fallback={<div>Loading stats...</div>}>
<CarStats makeId={make} />
</Suspense>
{cars.map(car => <CarCard key={car.id} car={car} />)}
</div>
);
}
// Inner component - shorter cache
async function CarStats({ makeId }: { makeId: string }) {
"use cache";
cacheLife("minutes");
const stats = await calculateStats(makeId);
return <StatsDisplay stats={stats} />;
}
Common Tasks
Converting Existing Component to Cache Component
Before:
// Regular server component
async function DataTable() {
const data = await fetchData();
return <Table data={data} />;
}
After:
// Cached server component
async function DataTable() {
"use cache";
cacheLife("hours");
cacheTag("data-table");
const data = await fetchData();
return <Table data={data} />;
}
// Parent with Suspense
export default function Page() {
return (
<Suspense fallback={<TableSkeleton />}>
<DataTable />
</Suspense>
);
}
Debugging Cache Issues
-
Component not caching:
- Verify "use cache" is first line
- Check Suspense boundary exists
- Ensure running Next.js 16+
- Check dev server logs
-
Cache not invalidating:
- Verify cacheTag is set correctly
- Check revalidateTag is called
- Review cacheLife settings
- Check if using "private" cache incorrectly
-
Runtime errors:
- Use Next.js runtime MCP tool to check errors
- Review browser console for hydration issues
- Check server logs for cache misses
Use Next.js DevTools MCP:
// Get runtime errors
mcp__next-devtools__nextjs_runtime({ action: "call_tool", toolName: "get_errors" })
Performance Optimization
Identify cache opportunities:
- Expensive data fetches: Wrap in "use cache"
- Static content: Use long cacheLife
- Frequently accessed: Cache with appropriate TTL
- User-specific: Use "use cache: private"
Built-in cacheLife Profiles
Next.js provides these profiles:
"seconds" // { stale: 1, revalidate: 10, expire: 60 }
"minutes" // { stale: 60, revalidate: 300, expire: 3600 }
"hours" // { stale: 3600, revalidate: 86400, expire: 604800 }
"days" // { stale: 86400, revalidate: 604800, expire: 2592000 }
"weeks" // { stale: 604800, revalidate: 2592000, expire: 31536000 }
"max" // { stale: 2592000, revalidate: 31536000, expire: Infinity }
Suspense Best Practices
1. Loading States
Provide meaningful fallbacks:
<Suspense fallback={<CarListSkeleton />}>
<CarList />
</Suspense>
2. Multiple Suspense Boundaries
Stream different parts independently:
export default function Dashboard() {
return (
<>
<Suspense fallback={<HeaderSkeleton />}>
<Header />
</Suspense>
<Suspense fallback={<ChartSkeleton />}>
<Charts />
</Suspense>
<Suspense fallback={<TableSkeleton />}>
<DataTable />
</Suspense>
</>
);
}
3. Error Boundaries with Suspense
import { ErrorBoundary } from "react-error-boundary";
export default function Page() {
return (
<ErrorBoundary fallback={<ErrorDisplay />}>
<Suspense fallback={<Loading />}>
<DataComponent />
</Suspense>
</ErrorBoundary>
);
}
Testing Cache Components
// __tests__/car-list.test.tsx
import { render, screen } from "@testing-library/react";
import { Suspense } from "react";
import CarList from "../car-list";
describe("CarList", () => {
it("renders with Suspense", async () => {
render(
<Suspense fallback={<div>Loading...</div>}>
<CarList />
</Suspense>
);
// Initially shows fallback
expect(screen.getByText("Loading...")).toBeInTheDocument();
// Wait for component to load
const content = await screen.findByText(/Toyota/i);
expect(content).toBeInTheDocument();
});
});
Common Errors and Solutions
Error: "use cache" must be first directive
Wrong:
async function Component() {
const data = await fetchData();
"use cache"; // ❌ Too late
}
Correct:
async function Component() {
"use cache"; // ✅ First line
const data = await fetchData();
}
Error: Missing Suspense boundary
Wrong:
export default function Page() {
return <CachedComponent />; // ❌ No Suspense
}
Correct:
export default function Page() {
return (
<Suspense fallback={<Loading />}>
<CachedComponent />
</Suspense>
);
}
Error: Dynamic rendering disables cache
Avoid dynamic APIs in cached components:
Wrong:
async function Component() {
"use cache";
const headers = await headers(); // ❌ Dynamic API
}
Correct:
// Move dynamic logic to parent
export default async function Page() {
const headers = await headers();
const userId = headers.get("x-user-id");
return (
<Suspense fallback={<Loading />}>
<CachedComponent userId={userId} />
</Suspense>
);
}
async function CachedComponent({ userId }: { userId: string }) {
"use cache";
// Now receives userId as prop
}
Documentation References
Always check the latest Next.js docs:
// Query Next.js documentation
mcp__next-devtools__nextjs_docs({
action: "get",
path: "/docs/app/api-reference/directives/use-cache"
})
Performance Monitoring
Track cache effectiveness:
- Check Next.js build output for cached routes
- Monitor server response times
- Use Next.js Analytics for performance metrics
- Review cache hit/miss ratios in logs
References
- Next.js 16 Cache Components: Use nextjs_docs MCP tool
- Related files:
apps/web/src/app/- All Next.js pagesapps/web/src/components/- React componentsapps/web/CLAUDE.md- Web app documentation
Best Practices
- Granular Caching: Cache at component level, not page level
- Appropriate TTLs: Match cache duration to data freshness needs
- Error Handling: Always wrap with ErrorBoundary
- Loading States: Provide meaningful Suspense fallbacks
- Cache Tags: Tag related caches for easy invalidation
- Testing: Test both cached and uncached states
- Monitoring: Track cache performance in production
- Progressive Enhancement: Start with long TTLs, optimize based on usage
Quick Install
/plugin add https://github.com/sgcarstrends/sgcarstrends/tree/main/cache-componentsCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
subagent-driven-development
DevelopmentThis skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.
algorithmic-art
MetaThis Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.
executing-plans
DesignUse the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.
cost-optimization
OtherThis Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.
