π What it is
yo yo test
cacheComponents is a new configuration flag introduced in Next.js 16 that changes how data fetching, caching, and pre-rendering behave inside the App Router.
In simple terms:
With cacheComponents enabled, pages are dynamic by default. Next.js can still pre-render a static shell and stream dynamic parts with Suspense; you opt into caching explicitly with use cache and related APIs where it helps. See the official guide: Next.js Cache Components.
βοΈ Configuration
To enable it, add the following to your next.config.ts (or .js):
typescript
With Cache Components, pages are dynamic by default; opt into caching with use cache and cacheLife where appropriate (docs).
π Effect on route segment config
When cacheComponents is enabled, several route segment options change behavior. Migrate as follows (docs):
- dynamic = "force-dynamic": Not needed. Pages are dynamic by default.
tsx
tsx
- dynamic = "force-static": Replace with
use cachein each layout/page for that route.
tsx
tsx
- revalidate: Replace with
cacheLifeinside the cached scope.
tsx
tsx
- fetchCache: Not needed. Inside a
use cachescope, server I/O andfetchare cached according to the cache boundary.
π‘ Why it exists
Before cacheComponents, Next.js aggressively cached and pre-rendered most data at build time or request time depending on fetch caching options. That worked well for static sites, but for dynamic, real-time applications (dashboards, AI apps, internal tools), this default often caused confusion and stale data issues.
So cacheComponents flips the default behavior:
Without it: Components are cached unless you disable it.
With it: Components are not cached unless you explicitly enable caching.
It's a major philosophical shift β giving developers full control over when and how caching happens.
π§© How it works conceptually
Cache Components implements Partial Prerendering (PPR) and introduces explicit cache boundaries with the use cache directive. The static shell can be pre-rendered while dynamic parts stream within Suspense boundaries (docs).
π§± Behavior overview
Here's what changes in the lifecycle when cacheComponents: true:
1. Data fetching defaults to dynamic
All fetch() calls and Server Component data requests are considered dynamic unless wrapped in a cache directive.
Example:
javascript
2. Caching must be explicit
If you want data to persist across requests, you must wrap it with use cache:
javascript
Now, getData() will be cached according to your app's cache policy.
3. Component trees are dynamically rendered
Components that fetch data are executed on every request. This ensures data freshness but can increase TTFB (time-to-first-byte) if your APIs are slow.
π§© Related APIs
cacheComponents works hand-in-hand with several other caching primitives:
| API / Directive | Purpose |
|---|---|
use cache | Marks a component, function, or page as cacheable. |
cacheLife() | Defines the lifespan (TTL) of cached data. |
cacheTag() | Tags cached data for selective revalidation. |
revalidateTag() | Triggers cache invalidation by tag. |
updateTag() | Marks a tag as updated to invalidate cached entries. |
revalidatePath() | Revalidates a specific route's cache entries. |
With cacheComponents: true, these APIs are no longer optional β they become core primitives for controlling data persistence.
βοΈ Tradeoffs
β Pros
- Always fresh data: no stale or outdated pre-renders.
- Predictable behavior: runtime fetching feels more "server-like."
- Fine-grained control: use
use cacheandcacheLife()for explicit caching. - Ideal for real-time or authenticated apps.
β Cons
- Increased latency: runtime fetching means slower TTFB if network-bound.
- Higher server cost: more frequent data fetching and computation.
- Requires explicit caching setup: you must consciously manage cache boundaries.
π When to use it
Use cacheComponents when your app fits one or more of these profiles:
| Use Case | Why it helps |
|---|---|
| Dashboards / Admin Panels | Always show live data; avoid stale API responses. |
| AI Applications | Model responses or content updates frequently. |
| Authenticated Apps | Avoid leaking cached content between users. |
| Internal Tools | Prioritize freshness over speed. |
| Complex real-time systems | Integrate with sockets, streams, or live APIs. |
π§ Example Scenarios
Without cacheComponents (default)
typescript
β
Fast.
β Might show stale numbers.
With cacheComponents: true
typescript
β
Always fresh.
β Slower unless wrapped with use cache.
If you later decide part of your data should be cached:
typescript
𧬠How it interacts with ISR & PPR
ISR still works β opt into caching with use cache and set duration with cacheLife. Cache Components implements PPR: the static shell can be pre-rendered while dynamic parts stream via Suspense. Use Suspense boundaries to control where streaming occurs. With Cache Components, caching and regeneration are opt-in at the function/component level (docs).
π§© Debugging & Observability
To verify how components are being cached:
- Run your app in development mode (
pnpm devornpm run dev). - Log or inspect requests with
console.log('cache hit/miss'). - Observe server logs for "rendered dynamically" messages.
πΊοΈ Migration Guide
If you're upgrading to Next.js 16:
- Start by enabling
cacheComponents: truein staging only. - Identify where stale data matters β those are safe to leave dynamic.
- Gradually wrap stable data fetches in
use cache. - Define cache lifetimes using
cacheLife()(e.g., 60 seconds for analytics). - Add
cacheTag()if you want fine-grained revalidation.
π§© Summary Table
| Feature | Default (before) | With cacheComponents |
|---|---|---|
| Data fetching | Static by default | Dynamic by default |
| Caching | Implicit | Explicit |
| Freshness | May be stale | Always fresh |
| Performance | Faster | Depends on runtime load |
| Use case | Static sites, blogs | Dynamic apps, dashboards |
π§ Quick Mental Model
| You want | Use |
|---|---|
| Always live data | cacheComponents: true |
| Cached data by default | Default (no flag) |
| Mix of both | Enable cacheComponents and mark selected parts with use cache |
π TL;DR
| Concept | Summary |
|---|---|
| cacheComponents | Makes components dynamic by default |
use cache | Opt-in caching for selective parts |
| Benefits | Fresh data, better control |
| Risks | More runtime cost, slower responses |
| Use when | Building dynamic, data-driven apps |
Mark this guide as complete to save it on your profile
Mark this guide as complete to save it on your profile