diff --git a/docs/01-app/03-api-reference/01-directives/use-cache-private.mdx b/docs/01-app/03-api-reference/01-directives/use-cache-private.mdx
new file mode 100644
index 00000000000000..03d25db25481c3
--- /dev/null
+++ b/docs/01-app/03-api-reference/01-directives/use-cache-private.mdx
@@ -0,0 +1,389 @@
+---
+title: 'use cache: private'
+description: 'Learn how to use the `"use cache: private"` directive to enable runtime prefetching of personalized content in your Next.js application.'
+version: canary
+related:
+ title: Related
+ description: View related API references.
+ links:
+ - app/api-reference/directives/use-cache
+ - app/api-reference/config/next-config-js/cacheComponents
+ - app/api-reference/functions/cacheLife
+ - app/api-reference/functions/cacheTag
+ - app/guides/prefetching
+---
+
+The `'use cache: private'` directive enables runtime prefetching of personalized content that depends on cookies, headers, or search params.
+
+> **Good to know:** `'use cache: private'` is a variant of [`use cache`](/docs/app/api-reference/directives/use-cache) designed specifically for user-specific content that needs to be prefetchable but should never be stored in server-side cache handlers.
+
+## Usage
+
+To use `'use cache: private'`, enable the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) flag in your `next.config.ts` file:
+
+```tsx filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ cacheComponents: true,
+}
+
+export default nextConfig
+```
+
+```jsx filename="next.config.js" switcher
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ cacheComponents: true,
+}
+
+export default nextConfig
+```
+
+Then add `'use cache: private'` to your function along with a `cacheLife` configuration and export `unstable_prefetch` from your page.
+
+### Basic example
+
+```tsx filename="app/product/[id]/page.tsx" switcher
+import { Suspense } from 'react'
+import { cookies } from 'next/headers'
+import { cacheLife, cacheTag } from 'next/cache'
+
+// REQUIRED: Enable runtime prefetching
+export const unstable_prefetch = {
+ mode: 'runtime',
+ samples: [
+ { params: { id: '1' }, cookies: [{ name: 'session-id', value: '1' }] },
+ ],
+}
+
+export default async function ProductPage({
+ params,
+}: {
+ params: Promise<{ id: string }>
+}) {
+ const { id } = await params
+
+ return (
+
+
+
Loading recommendations... }>
+
+
+
+ )
+}
+
+async function Recommendations({ productId }: { productId: string }) {
+ const recommendations = await getRecommendations(productId)
+
+ return (
+
+ {recommendations.map((rec) => (
+
+ ))}
+
+ )
+}
+
+async function getRecommendations(productId: string) {
+ 'use cache: private'
+ cacheTag(`recommendations-${productId}`)
+ cacheLife({ stale: 60 }) // Minimum 30 seconds required for runtime prefetch
+
+ // Access cookies within private cache functions
+ const sessionId = (await cookies()).get('session-id')?.value || 'guest'
+
+ return getPersonalizedRecommendations(productId, sessionId)
+}
+```
+
+```jsx filename="app/product/[id]/page.js" switcher
+import { Suspense } from 'react'
+import { cookies } from 'next/headers'
+import { cacheLife, cacheTag } from 'next/cache'
+
+// REQUIRED: Enable runtime prefetching
+export const unstable_prefetch = {
+ mode: 'runtime',
+ samples: [
+ { params: { id: '1' }, cookies: [{ name: 'session-id', value: '1' }] },
+ ],
+}
+
+export default async function ProductPage({ params }) {
+ const { id } = await params
+
+ return (
+
+
+
Loading recommendations... }>
+
+
+
+ )
+}
+
+async function Recommendations({ productId }) {
+ const recommendations = await getRecommendations(productId)
+
+ return (
+
+ {recommendations.map((rec) => (
+
+ ))}
+
+ )
+}
+
+async function getRecommendations(productId) {
+ 'use cache: private'
+ cacheTag(`recommendations-${productId}`)
+ cacheLife({ stale: 60 }) // Minimum 30 seconds required for runtime prefetch
+
+ // Access cookies within private cache functions
+ const sessionId = (await cookies()).get('session-id')?.value || 'guest'
+
+ return getPersonalizedRecommendations(productId, sessionId)
+}
+```
+
+> **Note:** Private caches require a `cacheLife` stale time of at least 30 seconds to enable runtime prefetching. Values below 30 seconds are treated as dynamic.
+
+## Difference from `use cache`
+
+While regular `use cache` is designed for static, shared content that can be cached on the server, `'use cache: private'` is specifically for dynamic, user-specific content that needs to be:
+
+1. **Personalized** - varies based on cookies, headers, or search params
+2. **Prefetchable** - can be loaded before the user navigates to the page
+3. **Client-only** - never persisted to server-side cache handlers
+
+| Feature | `use cache` | `'use cache: private'` |
+| ---------------------------------- | ---------------------- | ----------------------------------- |
+| **Access to `await cookies()`** | No | Yes |
+| **Access to `await headers()`** | No | Yes |
+| **Access to `await searchParams`** | No | Yes |
+| **Stored in cache handler** | Yes (server-side) | No (client-side only) |
+| **Runtime prefetchable** | N/A (already static) | Yes (when configured) |
+| **Cache scope** | Global (shared) | Per-user (isolated) |
+| **Use case** | Static, shared content | Personalized, user-specific content |
+
+## How it works
+
+### Runtime prefetching
+
+When a user hovers over or views a link to a page with `unstable_prefetch = { mode: 'runtime' }`:
+
+1. **Static content** is prefetched immediately (layouts, page shell)
+2. **Private cache functions** are executed with the user's current cookies/headers
+3. **Results are stored** in the client-side Resume Data Cache
+4. **Navigation is instant** - both static and personalized content are already loaded
+
+> **Good to know:** Without `'use cache: private'`, personalized content cannot be prefetched and must wait until after navigation completes. Runtime prefetching eliminates this delay by executing cache functions with the user's current request context.
+
+### Storage behavior
+
+Private caches are **never persisted** to server-side cache handlers (like Redis, Vercel Data Cache, etc.). They exist only to:
+
+1. Enable runtime prefetching of personalized content
+2. Store prefetched data in the client-side cache during the session
+3. Coordinate cache invalidation with tags and stale times
+
+This ensures user-specific data is never accidentally shared between users while still enabling fast, prefetched navigation.
+
+### Stale time requirements
+
+> **Note:** Functions with a `cacheLife` stale time less than 30 seconds will not be runtime prefetched, even when using `'use cache: private'`. This prevents prefetching of rapidly changing data that would likely be stale by navigation time.
+
+```tsx
+// Will be runtime prefetched (stale ≥ 30s)
+cacheLife({ stale: 60 })
+
+// Will be runtime prefetched (stale ≥ 30s)
+cacheLife({ stale: 30 })
+
+// Will NOT be runtime prefetched (stale < 30s)
+cacheLife({ stale: 10 })
+```
+
+## Request APIs allowed in private caches
+
+The following request-specific APIs can be used inside `'use cache: private'` functions:
+
+| API | Allowed in `use cache` | Allowed in `'use cache: private'` |
+| -------------- | ---------------------- | --------------------------------- |
+| `cookies()` | No | Yes |
+| `headers()` | No | Yes |
+| `searchParams` | No | Yes |
+| `connection()` | No | No |
+
+> **Note:** The [`connection()`](https://nextjs.org/docs/app/api-reference/functions/connection) API is prohibited in both `use cache` and `'use cache: private'` as it provides connection-specific information that cannot be safely cached.
+
+## Nesting rules
+
+Private caches have specific nesting rules to prevent user-specific data from leaking into shared caches:
+
+- Private caches **can** be nested inside other private caches
+- Private caches **cannot** be nested inside public caches (`'use cache'`, `'use cache: remote'`)
+- Public caches **can** be nested inside private caches
+
+```tsx
+// VALID: Private inside private
+async function outerPrivate() {
+ 'use cache: private'
+ const result = await innerPrivate()
+ return result
+}
+
+async function innerPrivate() {
+ 'use cache: private'
+ return getData()
+}
+
+// INVALID: Private inside public
+async function outerPublic() {
+ 'use cache'
+ const result = await innerPrivate() // Error!
+ return result
+}
+
+async function innerPrivate() {
+ 'use cache: private'
+ return getData()
+}
+```
+
+## Examples
+
+### Personalized product recommendations
+
+This example shows how to cache personalized product recommendations based on a user's session cookie. The recommendations are prefetched at runtime when the user hovers over product links.
+
+```tsx filename="app/product/[id]/page.tsx"
+import { cookies } from 'next/headers'
+import { cacheLife, cacheTag } from 'next/cache'
+
+export const unstable_prefetch = {
+ mode: 'runtime',
+ samples: [
+ { params: { id: '1' }, cookies: [{ name: 'user-id', value: 'user-123' }] },
+ ],
+}
+
+async function getRecommendations(productId: string) {
+ 'use cache: private'
+ cacheTag(`recommendations-${productId}`)
+ cacheLife({ stale: 60 })
+
+ const userId = (await cookies()).get('user-id')?.value
+
+ // Fetch personalized recommendations based on user's browsing history
+ const recommendations = await db.recommendations.findMany({
+ where: { userId, productId },
+ })
+
+ return recommendations
+}
+```
+
+### User-specific pricing
+
+Cache pricing information that varies by user tier, allowing instant navigation to the pricing page with personalized rates already loaded.
+
+```tsx filename="app/pricing/page.tsx"
+import { cookies } from 'next/headers'
+import { cacheLife } from 'next/cache'
+
+export const unstable_prefetch = {
+ mode: 'runtime',
+ samples: [{ cookies: [{ name: 'user-tier', value: 'premium' }] }],
+}
+
+async function getPricing() {
+ 'use cache: private'
+ cacheLife({ stale: 300 }) // 5 minutes
+
+ const tier = (await cookies()).get('user-tier')?.value || 'free'
+
+ // Return tier-specific pricing
+ return db.pricing.findMany({ where: { tier } })
+}
+```
+
+### Localized content based on headers
+
+Serve localized content based on the user's `Accept-Language` header, prefetching the correct language variant before navigation.
+
+```tsx filename="app/page.tsx"
+import { headers } from 'next/headers'
+import { cacheLife, cacheTag } from 'next/cache'
+
+export const unstable_prefetch = {
+ mode: 'runtime',
+ samples: [{ headers: [{ name: 'accept-language', value: 'en-US' }] }],
+}
+
+async function getLocalizedContent() {
+ 'use cache: private'
+ cacheTag('content')
+ cacheLife({ stale: 3600 }) // 1 hour
+
+ const headersList = await headers()
+ const locale = headersList.get('accept-language')?.split(',')[0] || 'en-US'
+
+ return db.content.findMany({ where: { locale } })
+}
+```
+
+### Search results with user preferences
+
+Prefetch search results that include user-specific preferences, ensuring personalized search results load instantly.
+
+```tsx filename="app/search/page.tsx"
+import { cookies } from 'next/headers'
+import { cacheLife } from 'next/cache'
+
+export const unstable_prefetch = {
+ mode: 'runtime',
+ samples: [
+ {
+ searchParams: { q: 'laptop' },
+ cookies: [{ name: 'preferences', value: 'compact-view' }],
+ },
+ ],
+}
+
+async function getSearchResults(query: string) {
+ 'use cache: private'
+ cacheLife({ stale: 120 }) // 2 minutes
+
+ const preferences = (await cookies()).get('preferences')?.value
+
+ // Apply user preferences to search results
+ return searchWithPreferences(query, preferences)
+}
+```
+
+> **Good to know**:
+>
+> - Private caches are ephemeral and only exist in the client-side cache for the session duration
+> - Private cache results are never written to server-side cache handlers
+> - The `unstable_prefetch` export is required for runtime prefetching to work
+> - A minimum stale time of 30 seconds is required for private caches to be prefetched
+> - You can use `cacheTag()` and `revalidateTag()` to invalidate private caches
+> - Each user gets their own private cache entries based on their cookies/headers
+
+## Platform Support
+
+| Deployment Option | Supported |
+| ------------------------------------------------------------------- | --------- |
+| [Node.js server](/docs/app/getting-started/deploying#nodejs-server) | Yes |
+| [Docker container](/docs/app/getting-started/deploying#docker) | Yes |
+| [Static export](/docs/app/getting-started/deploying#static-export) | No |
+| [Adapters](/docs/app/getting-started/deploying#adapters) | Yes |
+
+## Version History
+
+| Version | Changes |
+| --------- | ------------------------------------------------------------- |
+| `v16.0.0` | `'use cache: private'` introduced as an experimental feature. |
diff --git a/docs/01-app/03-api-reference/01-directives/use-cache.mdx b/docs/01-app/03-api-reference/01-directives/use-cache.mdx
index 05a02eba85aaf5..b0e920d2bff4d6 100644
--- a/docs/01-app/03-api-reference/01-directives/use-cache.mdx
+++ b/docs/01-app/03-api-reference/01-directives/use-cache.mdx
@@ -6,6 +6,7 @@ related:
title: Related
description: View related API references.
links:
+ - app/api-reference/directives/use-cache-private
- app/api-reference/config/next-config-js/cacheComponents
- app/api-reference/config/next-config-js/cacheLife
- app/api-reference/functions/cacheTag
@@ -15,6 +16,8 @@ related:
The `use cache` directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of function or component to cache the return value.
+> **Good to know:** For caching user-specific content that requires access to cookies or headers, see [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private).
+
## Usage
`use cache` is a Cache Components feature. To enable it, add the [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) option to your `next.config.ts` file:
@@ -104,6 +107,8 @@ When used at the top of a [layout](/docs/app/api-reference/file-conventions/layo
This means `use cache` cannot be used with [request-time APIs](/docs/app/getting-started/partial-prerendering#dynamic-rendering) like `cookies` or `headers`.
+> **Note:** If you need to cache content that depends on cookies, headers, or search params, use [`'use cache: private'`](/docs/app/api-reference/directives/use-cache-private) instead.
+
## `use cache` at runtime
On the **server**, the cache entries of individual components or functions will be cached in-memory.