Practical demonstration of field-level granular caching using Cache Components in Next.js 16.
๐ Spanish version: Leer en Espaรฑol
This project demonstrates how to cache individual fields of a record using different strategies in Next.js 16.
You have a product with three fields that change at different rates:
- Text (name + description): Rarely changes
- Price: Changes occasionally
- Stock: Must always be up to date
How do you cache each field independently?
Each field is implemented as a separate async component, with its own query and caching strategy.
// โ
Each field has its own strategy
<ProductText productId={id} /> // Cached for 1 week
<ProductPrice productId={id} /> // Cached for 1 hour
<Suspense>
<ProductStock productId={id} /> // No cache (streaming)
</Suspense>- โ Granular field-level caching โ Independent control over each data segment
- โ Separated queries โ One query per field, automatically optimized
- โ Tag-based revalidation โ Invalidate only what changed
- โ Static shell + Streaming โ Instant HTML + fresh runtime data
- โ Correct Suspense boundaries โ Clear examples of placement and reasoning
- โ Interactive demo โ Buttons to test live revalidation
- โ
Static product routes โ
generateStaticParamsreinforcing educational PPR - โ
Zod validation โ
productIdsanitization in Server Actions - โ Tailwind + shadcn/ui โ Modern, professional UI
- โ TypeScript โ Fully type-safe
- โ Mock DB with logs โ Observe when and how queries execute
ProductPage (parent - sync)
โ
โโ <Suspense>
โโ ProductContent (async - accesses params)
โโ ProductText (async + 'use cache' + cacheLife('weeks'))
โโ ProductPrice (async + 'use cache' + cacheLife('hours'))
โโ <Suspense>
โโ ProductStock (async without cache - streaming)
# Install dependencies
bun install
# Start development server
bun devOpen: http://localhost:3000
- The home page displays a product list
- Click any product
- Observe colored badges indicating cache behavior
- Open DevTools โ Network
- Disable cache
- Navigate to a product
- Notice:
- Initial HTML already contains text and price
- Stock arrives later via streaming
In your terminal:
[DB Query] ๐ getProductText - Product 1
[DB Query] ๐ฐ getProductPrice - Product 1
[DB Query] ๐ฆ getProductStock - Product 1
- Click "Revalidate Price"
- Refresh the page
- Only the price regenerates
- Text remains cached
// An async component IS a promise
async function ProductStock({ productId }) {
const stock = await db.getStock(productId);
return <div>{stock}</div>;
}
// Suspense must wrap it in the PARENT
<Suspense fallback="Loading...">
<ProductStock /> {/* โ This line creates the promise */}
</Suspense>;Yes, there are multiple queries โ but:
- Cached queries run at build time โ static shell
- Dynamic queries run at request time โ streaming
- Result: Improved perceived performance
// Cache with tag
cacheTag(`product-price-${productId}`);
// Revalidate only that field
revalidateTag(`product-price-${productId}`, "max");/docsโ Introduction/docs/implementationโ Full implementation/docs/conceptsโ Core concepts/docs/revalidationโupdateTagvsrevalidateTag/docs/benefitsโ Advantages
- Cache Components Documentation
- use cache directive
- cacheLife API
- cacheTag API
- revalidateTag API
- Next Skills
Cause: Async component without cache or Suspense
Fix: Add <Suspense> in the parent or 'use cache' inside the component
Cause: Browser cache enabled
Fix: Hard refresh (Ctrl + Shift + R) or use a private window
Cause: Incorrect tag
Fix: Ensure the tag is identical in both cache and revalidation:
cacheTag(`product-price-${productId}`);
revalidateTag(`product-price-${productId}`, "max");Contributions are welcome:
- Fork the repository
- Create a branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to your branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT
Created to demonstrate Cache Components in Next.js 16.
This project showcases advanced Next.js 16 patterns:
- Granular caching with
use cache - Proper Suspense boundaries
- Runtime data handling
- Selective tag-based revalidation
- Static shell + Streaming (PPR)
Use this repository as a reference for real-world implementations.