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.