Home
NextJS
NextJS - Cache Components
September 05, 2023
1 min

Table Of Contents

01
How Rendering Works with Cache Components
02
Automatically Prerendered Content
03
Deferring Rendering to Request Time
04
Using 'use cache'
05
Putting It All Together

Cache Components (opt-in via cacheComponents: true) introduce a rendering model called:

Partial Prerendering (PPR)

Next.js prerenders as much as possible at build time into a static HTML shell, then selectively streams or reuses dynamic pieces.

This gives you:

✅ Static-site speed
✅ Dynamic data where needed
✅ Smaller JS bundles

How Rendering Works with Cache Components

At build time, Next.js walks your component tree and asks:

“Can this complete without a request?”

If YES → prerender it into the static shell

If NO → you must choose:

  • Defer to request time with <Suspense>
  • Cache it with 'use cache'

If you don’t handle it explicitly, you’ll see:

Uncached data was accessed outside of <Suspense>

Automatically Prerendered Content

These are safe to execute during prerendering:

  • Pure computations
  • Local file reads
  • Static imports
  • Deterministic logic
import fs from 'node:fs'
export default async function Page() {
const content = fs.readFileSync('./config.json', 'utf-8')
const data = JSON.parse(content)
return <div>{data.title}</div>
}

➡ This becomes part of the static shell automatically.

Deferring Rendering to Request Time

If something needs live data (API, DB, etc.), wrap it in Suspense:

<Suspense fallback={<p>Loading...</p>}>
<DynamicContent />
</Suspense>

What happens:

  • Fallback → included in static shell
  • Real content → streamed at request time

This enables parallel rendering instead of blocking the page.

Using 'use cache'

This is the key feature.

It caches the result of an async function or component so it can be reused across requests.

import { cacheLife } from 'next/cache'
export default async function Page() {
'use cache'
cacheLife('hours')
const users = await db.query('SELECT * FROM users')
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}

Now:

✔ Runs once.
✔ Included in static shell.
✔ Reused across users.
✔ Revalidated later.

Using Cache with Runtime Data

const session = (await cookies()).get('session')?.value
return <CachedContent sessionId={session} />
async function CachedContent({ sessionId }) {
'use cache'
return fetchUserData(sessionId)
}

The argument becomes part of the cache key.

cacheTag()

Attach labels to cached data.

'use cache'
cacheTag('posts')

updateTag() — Immediate Refresh

Used after mutations (e.g., cart updates).

updateTag('cart')

Instantly invalidates and refreshes cache.

revalidateTag() — Background Refresh

revalidateTag('posts', 'max')

Fast response now, fresh data soon.

Putting It All Together

export default function BlogPage() {
return (
<>
<Header /> {/* Static */}
<BlogPosts /> {/* Cached */}
<Suspense fallback={<p>Loading preferences...</p>}>
<UserPreferences /> {/* Dynamic */}
</Suspense>
</>
)
}

Users see:

⚡ Instant layout.
⚡ Cached content ready.
⏳ Personalized data streams in.


Tags

#NextJS

Share

Related Posts

NextJS
NextJS - Data Fetching
September 06, 2023
1 min
© 2026, All Rights Reserved.
Powered By

Social Media

githublinkedinyoutube