use cache: private
'use cache: private' ディレクティブは、Cookie、ヘッダー、または検索パラメータに依存するパーソナライズされたコンテンツの実行時プリフェッチを有効にします。
参考情報:
'use cache: private'は、プリフェッチ可能である必要がありますが、サーバーサイドキャッシュハンドラーには決して保存されないユーザー固有のコンテンツ専用に設計された、use cacheのバリアントです。
使用方法
'use cache: private' を使用するには、next.config.ts ファイルで cacheComponents フラグを有効にします。
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfig次に、cacheLife 設定と共に 'use cache: private' を関数に追加し、ページから unstable_prefetch をエクスポートします。
基本的な例
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 (
<div>
<ProductDetails id={id} />
<Suspense fallback={<div>Loading recommendations...</div>}>
<Recommendations productId={id} />
</Suspense>
</div>
)
}
async function Recommendations({ productId }: { productId: string }) {
const recommendations = await getRecommendations(productId)
return (
<div>
{recommendations.map((rec) => (
<ProductCard key={rec.id} product={rec} />
))}
</div>
)
}
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)
}注意: プライベートキャッシュでは、実行時プリフェッチを有効にするために、少なくとも 30 秒の
cacheLifestale time が必要です。30 秒未満の値は動的として扱われます。
use cache との違い
通常の use cache は、サーバーでキャッシュできる静的で共有コンテンツ向けに設計されていますが、'use cache: private' は、動的でユーザー固有のコンテンツ向けに特別に設計されており、
- パーソナライズされた - Cookie、ヘッダー、または検索パラメータによって異なります
- プリフェッチ可能 - ユーザーがページに移動する前にロードできます
- クライアントのみ - サーバーサイドキャッシュハンドラーに永続化されることはありません
| 機能 | use cache | 'use cache: private' |
|---|---|---|
await cookies() へのアクセス | いいえ | はい |
await headers() へのアクセス | いいえ | はい |
await searchParams へのアクセス | いいえ | はい |
| キャッシュハンドラーに格納 | はい (サーバーサイド) | いいえ (クライアントサイドのみ) |
| 実行時プリフェッチ | N/A (すでに静的) | はい (設定時) |
| キャッシュスコープ | グローバル (共有) | ユーザーごと (分離) |
| ユースケース | 静的、共有コンテンツ | パーソナライズされた、ユーザー固有のコンテンツ |
仕組み
実行時プリフェッチ
ユーザーが unstable_prefetch = { mode: 'runtime' } のリンクにカーソルを合わせたり、表示したりすると
- 静的コンテンツ はすぐにプリフェッチされます (レイアウト、ページシェル)
- プライベートキャッシュ関数 は、ユーザーの現在の Cookie/ヘッダーで実行されます
- 結果は クライアントサイドの Resume Data Cache に保存されます
- ナビゲーションは瞬時です - 静的コンテンツとパーソナライズされたコンテンツの両方がすでにロードされています
参考情報:
'use cache: private'がないと、パーソナライズされたコンテンツはプリフェッチできず、ナビゲーションが完了するまで待つ必要があります。実行時プリフェッチは、ユーザーの現在のリクエストコンテキストでキャッシュ関数を実行することで、この遅延を解消します。
ストレージの挙動
プライベートキャッシュは、サーバーサイドキャッシュハンドラー (Redis、Vercel Data Cache など) には決して永続化されません。それらは、
- パーソナライズされたコンテンツの実行時プリフェッチを有効にする
- セッション中にプリフェッチされたデータをクライアントサイドキャッシュに保存する
- タグと stale time でキャッシュの無効化を調整する
これにより、ユーザー固有のデータがユーザー間で誤って共有されることを防ぎつつ、高速なプリフェッチナビゲーションを可能にします。
Stale time の要件
注意:
cacheLifestale time が 30 秒未満の関数は、'use cache: private'を使用している場合でも、実行時プリフェッチされません。これは、ナビゲーション時に stale になる可能性が高い、急速に変化するデータのプリフェッチを防ぐためです。
// 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 })プライベートキャッシュで許可されるリクエスト API
以下のリクエスト固有の API は、'use cache: private' 関数内で使用できます。
| API | use cache で許可 | 'use cache: private' で許可 |
|---|---|---|
cookies() | いいえ | はい |
headers() | いいえ | はい |
searchParams | いいえ | はい |
connection() | いいえ | いいえ |
注意:
connection()API は、安全にキャッシュできない接続固有の情報を提供するため、use cacheと'use cache: private'の両方で禁止されています。
ネストのルール
プライベートキャッシュには、ユーザー固有のデータが共有キャッシュに漏洩するのを防ぐための特定のネストルールがあります。
- プライベートキャッシュは、他のプライベートキャッシュの中にネストできます。
- プライベートキャッシュは、パブリックキャッシュ (
'use cache','use cache: remote') の中にネストできません。 - パブリックキャッシュは、プライベートキャッシュの中にネストできます。
// 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()
}例
パーソナライズされた商品レコメンデーション
この例では、ユーザーのセッション Cookie に基づいてパーソナライズされた商品レコメンデーションをキャッシュする方法を示します。レコメンデーションは、ユーザーが商品リンクにカーソルを合わせたときに実行時にプリフェッチされます。
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
}ユーザー固有の価格設定
ユーザーのティアによって異なる価格情報をキャッシュし、パーソナライズされたレートがすでにロードされた価格ページへの即時ナビゲーションを可能にします。
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 } })
}ヘッダーに基づくローカライズされたコンテンツ
ユーザーの Accept-Language ヘッダーに基づいてローカライズされたコンテンツを提供し、ナビゲーション前に正しい言語バリアントをプリフェッチします。
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 } })
}ユーザー設定に基づいた検索結果
ユーザー固有の設定を含む検索結果をプリフェッチし、パーソナライズされた検索結果が瞬時にロードされるようにします。
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)
}知っておくと良いこと:
- プライベートキャッシュは一時的であり、セッション期間中はクライアントサイドキャッシュにのみ存在します。
- プライベートキャッシュの結果は、サーバーサイドキャッシュハンドラーに書き込まれることはありません。
- 実行時プリフェッチを機能させるには、
unstable_prefetchエクスポートが必要です。- プライベートキャッシュをプリフェッチするには、最低 30 秒の stale time が必要です。
cacheTag()およびrevalidateTag()を使用して、プライベートキャッシュを無効化できます。- 各ユーザーは、Cookie/ヘッダーに基づいて独自のプライベートキャッシュエントリを取得します。
プラットフォームのサポート
| デプロイメントオプション | サポート |
|---|---|
| Node.jsサーバー | はい |
| Dockerコンテナ | はい |
| 静的エクスポート | いいえ |
| アダプター | はい |
バージョン履歴
| バージョン | 変更履歴 |
|---|---|
v16.0.0 | 'use cache: private' が実験的機能として導入されました。 |
関連
役に立ちましたか?