コンテンツにスキップ
App Routerガイドキャッシング

Next.jsでのキャッシング

Next.jsは、レンダリング作業とデータリクエストをキャッシュすることにより、アプリケーションのパフォーマンスを向上させ、コストを削減します。このページでは、Next.jsのキャッシングメカニズム、それらを構成するために使用できるAPI、およびそれらが互いにどのように相互作用するかについて詳しく説明します。

知っておくと良いこと:このページは、Next.jsの内部動作を理解するのに役立ちますが、Next.jsを生産的に使用するために不可欠な知識ではありません。Next.jsのキャッシングヒューリスティックのほとんどは、APIの使用状況によって決定され、ゼロまたは最小限の設定で最高のパフォーマンスを発揮するようにデフォルト設定されています。代わりに例にジャンプしたい場合は、ここから開始してください

概要

さまざまなキャッシングメカニズムとその目的についての概要を以下に示します。

メカニズム内容場所目的期間
リクエストのメモ化関数の戻り値サーバーReactコンポーネントツリー内のデータを再利用するリクエストごとのライフサイクル
データキャッシュデータサーバーユーザーリクエストやデプロイメントをまたいでデータを保存する永続的(再検証可能)
フルルートキャッシュHTMLおよびRSCペイロードサーバーレンダリングコストを削減し、パフォーマンスを向上させる永続的(再検証可能)
ルーターキャッシュRSCペイロードクライアントナビゲーション時のサーバーリクエストを削減するユーザーセッションまたは時間ベース

デフォルトでは、Next.jsはパフォーマンスを向上させ、コストを削減するために可能な限りキャッシュします。これは、ルートが静的にレンダリングされ、データリクエストがキャッシュされることを意味します。オプトアウトしない限り。以下の図は、デフォルトのキャッシング動作を示しています。ルートがビルド時に静的にレンダリングされる場合と、静的ルートが最初にアクセスされた場合です。

Diagram showing the default caching behavior in Next.js for the four mechanisms, with HIT, MISS and SET at build time and when a route is first visited.

キャッシングの動作は、ルートが静的にレンダリングされるか動的にレンダリングされるか、データがキャッシュされるかキャッシュされないか、およびリクエストが初期アクセスの一部か後続のナビゲーションの一部かによって異なります。ユースケースに応じて、個々のルートとデータリクエストのキャッシング動作を構成できます。

Fetchキャッシングはproxyではサポートされていません。proxy内で行われたすべてのfetchはキャッシュされません。

レンダリング戦略

Next.jsでのキャッシングの仕組みを理解するには、利用可能なレンダリング戦略を理解することが役立ちます。レンダリング戦略は、ルートのHTMLがいつ生成されるかを決定し、これはキャッシュできるものに直接影響します。

静的レンダリング

静的レンダリングでは、ルートはビルド時またはデータ再検証後のバックグラウンドでレンダリングされます。結果はキャッシュされ、リクエスト間で再利用できます。静的ルートは、フルルートキャッシュに完全にキャッシュされます。

動的レンダリング

動的レンダリングでは、ルートはリクエスト時にレンダリングされます。これは、ルートがcookie、ヘッダー、または検索パラメータなどのリクエスト固有の情報を使用する場合に発生します。

ルートがこれらのAPIのいずれかを使用すると、動的になります

動的ルートはフルルートキャッシュにはキャッシュされませんが、データリクエストにはデータキャッシュを使用できます。

知っておくと良いことキャッシュコンポーネントを使用して、同じルート内で静的レンダリングと動的レンダリングを混在させることができます。

リクエストのメモ化

Next.jsはfetch APIを拡張し、同じURLとオプションを持つリクエストを自動的にメモ化します。これは、Reactコンポーネントツリーの複数の場所で同じデータに対してfetch関数を呼び出すことができ、1回だけ実行されることを意味します。

Deduplicated Fetch Requests

たとえば、ルート全体で同じデータを使用する必要がある場合(例:レイアウト、ページ、および複数のコンポーネント)、ツリーの上部でデータをフェッチして、コンポーネント間でプロップを転送する必要はありません。代わりに、同じデータに対して複数のネットワークリクエストを行うパフォーマンスへの影響を心配することなく、それらを必要とするコンポーネントでデータをフェッチできます。

app/example.tsx
async function getItem() {
  // The `fetch` function is automatically memoized and the result
  // is cached
  const res = await fetch('https://.../item/1')
  return res.json()
}
 
// This function is called twice, but only executed the first time
const item = await getItem() // cache MISS
 
// The second call could be anywhere in your route
const item = await getItem() // cache HIT

リクエストメモ化の仕組み

Diagram showing how fetch memoization works during React rendering.
  • ルートをレンダリングする際、特定のリクエストが最初に呼び出されると、その結果はメモリになく、キャッシュMISSになります。
  • そのため、関数が実行され、データが外部ソースからフェッチされ、結果がメモリに格納されます。
  • 同じレンダリングパスでの後続の関数呼び出しは、キャッシュHITとなり、関数を実行せずにメモリからデータが返されます。
  • ルートのレンダリングが完了し、レンダリングパスが完了すると、メモリは「リセット」され、すべてリクエストメモ化エントリはクリアされます。

知っておくと良いこと:

  • リクエストメモ化はNext.jsの機能ではなくReactの機能です。他のキャッシングメカニズムとの相互作用を示すためにここに含めました。
  • メモ化はfetchリクエストのGETメソッドにのみ適用されます。
  • メモ化はReactコンポーネントツリーにのみ適用されます。これは意味します
    • generateMetadatagenerateStaticParams、レイアウト、ページ、およびその他のサーバーコンポーネントでのfetchリクエストに適用されます。
    • ルートハンドラーでのfetchリクエストには適用されません。それらはReactコンポーネントツリーの一部ではないためです。
  • fetchが適さない場合(例:一部のデータベースクライアント、CMSクライアント、またはGraphQLクライアント)、Reactcache関数を使用して関数をメモ化できます。

期間

キャッシュは、Reactコンポーネントツリーのレンダリングが完了するまで、サーバーリクエストのライフタイム続きます。

再検証

メモ化はサーバーリクエスト間で共有されず、レンダリング中にのみ適用されるため、再検証する必要はありません。

オプトアウト

メモ化はfetchリクエストのGETメソッドにのみ適用され、POSTDELETEなどの他のメソッドはメモ化されません。このデフォルトの動作はReactの最適化であり、オプトアウトすることは推奨しません。

個々のリクエストを管理するには、AbortControllersignalプロパティを使用できます。

app/example.js
const { signal } = new AbortController()
fetch(url, { signal })

データキャッシュ

Next.jsには、サーバーリクエストデプロイメントをまたいでデータフェッチの結果を永続化する組み込みのデータキャッシュがあります。これは、Next.jsがネイティブfetchAPIを拡張して、サーバー上の各リクエストが独自の永続キャッシングセマンティクスを設定できるようにするため可能です。

知っておくと良いこと:ブラウザでは、fetchcacheオプションは、リクエストがブラウザのHTTPキャッシュとどのように相互作用するかを示しますが、Next.jsでは、cacheオプションは、サーバーサイドリクエストがサーバーのデータキャッシュとどのように相互作用するかを示します。

fetchcacheおよびnext.revalidateオプションを使用して、キャッシング動作を構成できます。

開発モードでは、fetchデータはホットモジュールリプレースメント(HMR)のために再利用され、キャッシュオプションはハードリフレッシュでは無視されます。

データキャッシュの仕組み

Diagram showing how cached and uncached fetch requests interact with the Data Cache. Cached requests are stored in the Data Cache, and memoized, uncached requests are fetched from the data source, not stored in the Data Cache, and memoized.
  • 'force-cache'オプション付きのfetchリクエストがレンダリング中に最初に呼び出されると、Next.jsはデータキャッシュにキャッシュされた応答があるか確認します。
  • キャッシュされた応答が見つかった場合、それはすぐに返され、メモ化されます。
  • キャッシュされた応答が見つからない場合、データソースへのリクエストが行われ、結果がデータキャッシュに格納され、メモ化されます。
  • キャッシュされないデータ(例:cacheオプションが定義されていない、または{ cache: 'no-store' }を使用している)の場合、結果は常にデータソースからフェッチされ、メモ化されます。
  • データがキャッシュされているかキャッシュされていないかに関わらず、Reactレンダリングパス中に同じデータに対する重複リクエストを回避するために、リクエストは常にメモ化されます。

データキャッシュとリクエストメモ化の違い

どちらのキャッシングメカニズムもキャッシュされたデータを再利用してパフォーマンスを向上させますが、データキャッシュは着信リクエスト間で永続化されるのに対し、メモ化はリクエストのライフタイムのみ持続します。

期間

データキャッシュは、再検証またはオプトアウトしない限り、着信リクエストおよびデプロイメント間で永続化されます。

再検証

キャッシュされたデータは、次の2つの方法で再検証できます。

  • 時間ベースの再検証:一定時間が経過し、新しいリクエストが行われた後にデータを再検証します。これは、変更が頻繁でないデータや、鮮度がそれほど重要でない場合に便利です。
  • オンデマンド再検証:イベント(例:フォーム送信)に基づいてデータを再検証します。オンデマンド再検証は、タグベースまたはパスベースのアプローチを使用して、データグループを一度に再検証できます。これは、最新のデータが可能な限り早く表示されることを保証したい場合(例:ヘッドレスCMSからのコンテンツが更新されたとき)に便利です。

時間ベースの再検証

時間間隔でデータを再検証するには、fetchnext.revalidateオプションを使用して、リソースのキャッシュ期間(秒単位)を設定できます。

// Revalidate at most every hour
fetch('https://...', { next: { revalidate: 3600 } })

または、ルートセグメント構成オプションを使用して、セグメント内のすべてのfetchリクエストを構成するか、fetchを使用できない場合(例:データベースクライアント、サードパーティライブラリ)に使用できます。

時間ベースの再検証の仕組み

Diagram showing how time-based revalidation works, after the revalidation period, stale data is returned for the first request, then data is revalidated.
  • revalidate付きのfetchリクエストが最初に呼び出されると、データは外部データソースからフェッチされ、データキャッシュに格納されます。
  • 指定された期間内(例:60秒)に呼び出されたリクエストは、キャッシュされたデータを返します。
  • 期間経過後、次回の要求は(古い)キャッシュされたデータを返します。
    • Next.jsはバックグラウンドでデータの再検証をトリガーします。
    • バックグラウンド再検証が成功すると、Next.jsはデータキャッシュを最新のデータで更新します。
    • バックグラウンド再検証が失敗した場合、以前のデータは変更されずに保持されます。

これはstale-while-revalidateの動作と似ています。

オンデマンド再検証

データは、パス(revalidatePath)またはキャッシュタグ(revalidateTag)によってオンデマンドで再検証できます。

オンデマンド再検証の仕組み

Diagram showing how on-demand revalidation works, the Data Cache is updated with fresh data after a revalidation request.
  • fetchリクエストが最初に呼び出されると、データは外部データソースからフェッチされ、データキャッシュに格納されます。
  • オンデマンド再検証がトリガーされると、適切なキャッシュエントリがキャッシュからパージされます。
    • これは、古いデータを新しいデータがフェッチされるまでキャッシュに保持する時間ベースの再検証とは異なります。
  • 次回の要求は再びキャッシュMISSとなり、データは外部データソースからフェッチされ、データキャッシュに格納されます。

オプトアウト

fetchからの応答をキャッシュしたくない場合は、次のことができます。

let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })

フルルートキャッシュ

関連用語:

自動静的最適化静的サイト生成、または静的レンダリングという用語は、アプリケーションのルートをビルド時にレンダリングおよびキャッシュするプロセスを指すために、同義で使われることがあります。

Next.jsはルートを自動的にレンダリングおよびキャッシュします。これは、各リクエストでレンダリングする代わりにキャッシュされたルートを提供できる最適化であり、ページロードが高速になります。

フルルートキャッシュの仕組みを理解するには、Reactがレンダリングをどのように処理するか、およびNext.jsがその結果をどのようにキャッシュするかを見るのが役立ちます。

1. サーバーでのReactレンダリング

サーバーでは、Next.jsはReactのAPIを使用してレンダリングをオーケストレーションします。レンダリング作業は、個々のルートセグメントとSuspense境界によってチャンクに分割されます。

各チャンクは2つのステップでレンダリングされます。

  1. Reactは、サーバーコンポーネントを、ストリーミング用に最適化された特別なデータ形式であるReact Server Component Payloadにレンダリングします。
  2. Next.jsは、React Server Component PayloadとClient Component JavaScript命令を使用して、サーバーでHTMLをレンダリングします。

これは、作業をキャッシュしたり、応答を送信したりする前に、すべてのレンダリングが完了するのを待つ必要がないことを意味します。代わりに、作業が完了したときにストリーミング応答を送信できます。

React Server Component Payloadとは何ですか?

React Server Component Payloadは、レンダリングされたReact Server Componentsツリーのコンパクトなバイナリ表現です。ブラウザのDOMを更新するために、クライアントでReactによって使用されます。React Server Component Payloadには以下が含まれます。

  • サーバーコンポーネントのレンダリング結果
  • クライアントコンポーネントのレンダリング場所のプレースホルダーとそれらのJavaScriptファイルへの参照
  • サーバーコンポーネントからクライアントコンポーネントに渡されたプロップ

詳細については、サーバーコンポーネントのドキュメントを参照してください。

2. サーバーでのNext.jsキャッシング(フルルートキャッシュ)

Default behavior of the Full Route Cache, showing how the React Server Component Payload and HTML are cached on the server for statically rendered routes.

Next.jsのデフォルトの動作は、ルートのレンダリング結果(React Server Component PayloadおよびHTML)をサーバーにキャッシュすることです。これは、ビルド時に静的にレンダリングされたルート、または再検証中に適用されます。

3. クライアントでのReactハイドレーションと競合検出

リクエスト時、クライアントで

  1. HTMLは、クライアントコンポーネントとサーバーコンポーネントの高速でインタラクティブでない初期プレビューをすぐに表示するために使用されます。
  2. React Server Component Payloadは、クライアントとレンダリングされたサーバーコンポーネントツリーを競合させ、DOMを更新するために使用されます。
  3. JavaScript命令は、クライアントコンポーネントをハイドレートしてアプリケーションをインタラクティブにするために使用されます。

4. クライアントでのNext.jsキャッシング(ルーターキャッシュ)

React Server Component Payloadは、クライアントサイドのルーターキャッシュに格納されます。これは、個々のルートセグメントごとに分割された別のインメモリキャッシュです。このルーターキャッシュは、以前にアクセスしたルートを保存し、将来のルートをプリフェッチすることで、ナビゲーションエクスペリエンスを向上させるために使用されます。

後続のナビゲーション

後続のナビゲーション中やプリフェッチ中に、Next.jsはルーターキャッシュにReact Server Component Payloadが格納されているか確認します。格納されている場合、サーバーへの新しいリクエストの送信をスキップします。

ルートセグメントがキャッシュにない場合、Next.jsはサーバーからReact Server Component Payloadをフェッチし、クライアントでルーターキャッシュをポップレートします。

静的および動的レンダリング

ビルド時にルートがキャッシュされるかどうかの判断は、静的にレンダリングされるか動的にレンダリングされるかによって異なります。静的ルートはデフォルトでキャッシュされますが、動的ルートはリクエスト時にレンダリングされ、キャッシュされません。

この図は、静的および動的にレンダリングされたルート、およびキャッシュされたデータとキャッシュされていないデータの違いを示しています。

How static and dynamic rendering affects the Full Route Cache. Static routes are cached at build time or after data revalidation, whereas dynamic routes are never cached

静的および動的レンダリングについてさらに学習します。

期間

デフォルトでは、フルルートキャッシュは永続的です。これは、レンダリング出力がユーザーリクエスト間でキャッシュされることを意味します。

無効化

フルルートキャッシュを無効化するには、次の2つの方法があります。

  • データ再検証データキャッシュを再検証すると、サーバーでコンポーネントが再レンダリングされ、新しいレンダリング出力がキャッシュされるため、ルーターキャッシュも無効化されます。
  • 再デプロイ:データキャッシュとは異なり、デプロイメントをまたいで永続化されますが、フルルートキャッシュは新しいデプロイメントでクリアされます。

オプトアウト

フルルートキャッシュをオプトアウトする、つまり、すべての着信リクエストに対してコンポーネントを動的にレンダリングするには、次の方法で行います。

  • 動的APIの使用:これにより、ルートはフルルートキャッシュからオプトアウトされ、リクエスト時に動的にレンダリングされます。データキャッシュは引き続き使用できます。
  • dynamic = 'force-dynamic'またはrevalidate = 0ルートセグメント構成オプションの使用:これにより、フルルートキャッシュとデータキャッシュがスキップされます。つまり、コンポーネントはサーバーへのすべての着信リクエストでレンダリングされ、データがフェッチされます。ルーターキャッシュはクライアントサイドキャッシュであるため、引き続き適用されます。
  • データキャッシュのオプトアウト:ルートにキャッシュされていないfetchリクエストがある場合、これはルートをフルルートキャッシュからオプトアウトします。特定のfetchリクエストのデータは、すべての着信リクエストに対してフェッチされます。キャッシュを明示的に有効にした他のfetchリクエストは、引き続きデータキャッシュにキャッシュされます。これにより、キャッシュされたデータとキャッシュされていないデータのハイブリッドが可能になります。

クライアントサイドルーターキャッシュ

Next.jsには、レイアウト、ローディング状態、およびページによって分割されたルートセグメントのRSCペイロードを格納する、インメモリのクライアントサイドルーターキャッシュがあります。

ユーザーがルート間をナビゲートすると、Next.jsは訪問したルートセグメントをキャッシュし、ユーザーがナビゲートする可能性のあるルートをプリフェッチします。これにより、即時的な前後ナビゲーション、ナビゲーション間のフルページリロードなし、共有レイアウトでのブラウザ状態とReact状態の保存が実現されます。

ルーターキャッシュの場合

  • レイアウトはキャッシュされ、ナビゲーションで再利用されます(部分レンダリング)。
  • ローディング状態はキャッシュされ、ナビゲーションで即時ナビゲーションのために再利用されます。
  • ページはデフォルトではキャッシュされませんが、ブラウザの前後ナビゲーション中に再利用されます。実験的なstaleTimes構成オプションを使用して、ページセグメントのキャッシュを有効にできます。

知っておくと良いこと:このキャッシュはNext.jsとServer Componentsに特に関連しており、ブラウザのbfcacheとは異なりますが、似た結果をもたらします。

期間

キャッシュはブラウザの一時メモリに格納されます。ルーターキャッシュの持続期間は、次の2つの要因によって決まります。

  • セッション:キャッシュはナビゲーション全体で永続化されます。ただし、ページリフレッシュ時にクリアされます。
  • 自動無効化期間:レイアウトとローディング状態のキャッシュは、特定の時間が経過すると自動的に無効化されます。期間は、リソースがプリフェッチされた方法と、リソースが静的に生成されたかによって異なります。
    • デフォルトのプリフェッチprefetch={null}または指定なし):動的ページではキャッシュされません。静的ページでは5分。
    • フルプリフェッチprefetch={true}またはrouter.prefetch):静的および動的ページの両方で5分。

ページリフレッシュはすべてのキャッシュされたセグメントをクリアしますが、自動無効化期間は、セグメントがプリフェッチされた時点から個々のセグメントにのみ影響します。

知っておくと良いこと:実験的なstaleTimes構成オプションを使用して、上記自動無効化時間を調整できます。

無効化

ルーターキャッシュを無効化するには、次の2つの方法があります。

  • サーバーアクション
    • パスによるオンデマンド再検証(revalidatePath)またはキャッシュタグによる(revalidateTag
    • cookies.setまたはcookies.deleteを使用して、Cookieを使用するルートが古くなるのを防ぐためにルーターキャッシュを無効化します(例:認証の反映)。
  • router.refreshを呼び出すと、ルーターキャッシュが無効化され、現在のルートのサーバーへの新しいリクエストが行われます。

オプトアウト

Next.js 15以降、ページセグメントはデフォルトでオプトアウトされます。

知っておくと良いこと:<Link>コンポーネントのprefetchプロップをfalseに設定して、プリフェッチをオプトアウトすることもできます。

キャッシュの相互作用

さまざまなキャッシングメカニズムを構成する際には、それらが互いにどのように相互作用するかを理解することが重要です。

データキャッシュとフルルートキャッシュ

  • データキャッシュの再検証またはオプトアウトは、レンダリング出力がデータに依存するため、フルルートキャッシュを無効化します
  • フルルートキャッシュの無効化またはオプトアウトは、データキャッシュに影響しません。キャッシュされたデータとキャッシュされていないデータの両方を持つルートを動的にレンダリングできます。これは、ページのほとんどがキャッシュされたデータを使用するが、リクエスト時にフェッチする必要があるデータに依存するコンポーネントがいくつかある場合に便利です。すべてのデータを再フェッチするパフォーマンスへの影響を心配することなく、動的にレンダリングできます。

データキャッシュとクライアントサイドルーターキャッシュ

  • データキャッシュとルーターキャッシュを即座に無効化するには、revalidatePathまたはrevalidateTagサーバーアクションで使用できます。
  • ルートハンドラーでのデータキャッシュの再検証は、ルートハンドラーが特定のルートに紐づいていないため、ルーターキャッシュを即座に無効化しません。これは、ルーターキャッシュがハードリフレッシュまたは自動無効化期間が経過するまで、前のペイロードを提供し続けることを意味します。

API

次の表は、さまざまなNext.js APIがキャッシングにどのように影響するかをまとめたものです。

APIルーターキャッシュフルルートキャッシュデータキャッシュReact Cache
<Link prefetch>キャッシュ
router.prefetchキャッシュ
router.refresh再検証
fetchキャッシュキャッシュ (GET および HEAD)
fetch options.cacheキャッシュまたはオプトアウト
fetch options.next.revalidate再検証再検証
fetch options.next.tagsキャッシュキャッシュ
revalidateTag再検証(サーバーアクション)再検証再検証
revalidatePath再検証(サーバーアクション)再検証再検証
const revalidate再検証またはオプトアウト再検証またはオプトアウト
const dynamicキャッシュまたはオプトアウトキャッシュまたはオプトアウト
cookies再検証(サーバーアクション)オプトアウト
headers, searchParamsオプトアウト
generateStaticParamsキャッシュ
React.cacheキャッシュ
unstable_cacheキャッシュ

デフォルトでは、<Link>コンポーネントはフルルートキャッシュからルートを自動的にプリフェッチし、ルーターキャッシュにReact Server Component Payloadを追加します。

プリフェッチを無効にするには、prefetchプロップをfalseに設定できます。ただし、これによりキャッシュが永続的にスキップされるわけではありません。ユーザーがルートにアクセスすると、ルートセグメントは引き続きクライアントサイドでキャッシュされます。

<Link>コンポーネントについてさらに学習します。

router.prefetch

useRouterフックのprefetchオプションを使用して、ルートを手動でプリフェッチできます。これにより、React Server Component Payloadがルーターキャッシュに追加されます。

useRouterフックのAPIリファレンスを参照してください。

router.refresh

useRouterフックのrefreshオプションを使用して、ルートをマニュアルでリフレッシュできます。これにより、ルーターキャッシュが完全にクリアされ、現在のルートのサーバーへの新しいリクエストが行われます。refreshはデータキャッシュやフルルートキャッシュには影響しません。

レンダリング結果は、React状態とブラウザ状態を保持しながらクライアントで競合検出されます。

useRouterフックのAPIリファレンスを参照してください。

fetch

fetchから返されるデータは、データキャッシュに自動的にキャッシュされません

デフォルトでは、cacheまたはnext.revalidateオプションが指定されていない場合

  • 動的レンダリング:Fetchは各リクエストで実行され、常に最新のデータを返します。
  • 静的レンダリング:フェッチされたデータはデータキャッシュに格納され、レンダリング出力はフルルートキャッシュに格納されます。Next.jsは、パスが再検証されるまで、このキャッシュされた結果を提供します。

その他のオプションについては、fetch APIリファレンスを参照してください。

fetch options.cache

cacheオプションをforce-cacheに設定することで、個々のfetchをキャッシュにオプトインできます。

// Opt into caching
fetch(`https://...`, { cache: 'force-cache' })

その他のオプションについては、fetch APIリファレンスを参照してください。

fetch options.next.revalidate

fetchnext.revalidateオプションを使用して、個々のfetchリクエストの再検証期間(秒単位)を設定できます。これにより、データキャッシュが再検証され、それがフルルートキャッシュを再検証します。最新のデータがフェッチされ、コンポーネントがサーバーで再レンダリングされます。

// Revalidate at most after 1 hour
fetch(`https://...`, { next: { revalidate: 3600 } })

その他のオプションについては、fetch APIリファレンスを参照してください。

fetch options.next.tags および revalidateTag

Next.jsには、きめ細やかなデータキャッシングと再検証のためのキャッシュタグ付けシステムがあります。

  1. fetchまたはunstable_cacheを使用する場合、キャッシュエントリに1つ以上のタグを付けるオプションがあります。
  2. その後、revalidateTagを呼び出して、そのタグに関連付けられたキャッシュエントリをパージできます。

たとえば、データをフェッチする際にタグを設定できます。

// Cache data with a tag
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })

次に、タグを指定してrevalidateTagを呼び出し、キャッシュエントリをパージします。

// Revalidate entries with a specific tag
revalidateTag('a')

revalidateTagは、達成したいことに応じて、次の2つの場所で使用できます。

  1. ルートハンドラー - サードパーティのイベント(例:Webhook)に応答してデータを再検証します。これは、ルーターキャッシュを即座に無効化しません。ルーターハンドラーは特定のルートに紐づいていないためです。
  2. サーバーアクション - ユーザーアクション(例:フォーム送信、ボタンクリック)後にデータを再検証します。これは、関連するルートのルーターキャッシュを無効化します。

revalidatePath

revalidatePathを使用すると、データおよび特定のパスの下のルートセグメントを1つの操作で手動で再検証できます。revalidatePathメソッドを呼び出すと、データキャッシュが再検証され、それがフルルートキャッシュを無効化します。

revalidatePath('/')

revalidatePathは、達成したいことに応じて、次の2つの場所で使用できます。

  1. ルートハンドラー - サードパーティのイベント(例:Webhook)に応答してデータを再検証します。
  2. サーバーアクション - ユーザーインタラクション(例:フォーム送信、ボタンクリック)後にデータを再検証します。

詳細については、revalidatePath APIリファレンスを参照してください。

revalidatePath vs. router.refresh

router.refreshを呼び出すと、ルーターキャッシュがクリアされ、データキャッシュやフルルートキャッシュを無効化せずにサーバーでルートセグメントが再レンダリングされます。

違いは、revalidatePathはデータキャッシュとフルルートキャッシュをパージするのに対し、router.refresh()はクライアントサイドAPIであるため、データキャッシュとフルルートキャッシュを変更しないことです。

動的API

cookiesheadersなどの動的API、およびページでのsearchParamsプロップは、ランタイムの着信リクエスト情報に依存します。それらを使用すると、ルートはフルルートキャッシュからオプトアウトされます。つまり、ルートは動的にレンダリングされます。

cookies

サーバーアクションでのcookies.setまたはcookies.deleteの使用は、Cookieを使用するルートが古くなるのを防ぐためにルーターキャッシュを無効化します(例:認証変更を反映するため)。

cookies APIリファレンスを参照してください。

セグメント構成オプション

ルートセグメント構成オプションは、ルートセグメントのデフォルトをオーバーライドするために使用できるか、またはfetch APIを使用できない場合(例:データベースクライアントまたはサードパーティライブラリ)に使用できます。

次のルートセグメント構成オプションは、フルルートキャッシュからオプトアウトします。

  • const dynamic = 'force-dynamic'

この構成オプションは、すべてのfetchをデータキャッシュからオプトアウトします(つまり、no-store)。

  • const fetchCache = 'default-no-store'

より高度なオプションについては、fetchCacheを参照してください。

その他のオプションについては、ルートセグメント構成のドキュメントを参照してください。

generateStaticParams

動的セグメント(例:app/blog/[slug]/page.js)の場合、generateStaticParamsによって提供されるパスは、ビルド時にフルルートキャッシュにキャッシュされます。リクエスト時に、Next.jsはビルド時に知られていなかったパスも、最初にアクセスされたときにキャッシュします。

ビルド時にすべてのパスを静的にレンダリングするには、generateStaticParamsにパスの完全なリストを指定します。

app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

ビルド時にパスの一部を静的にレンダリングし、残りを実行時に最初にアクセスされたときにレンダリングするには、パスのサブセットを返します。

app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  // Render the first 10 posts at build time
  return posts.slice(0, 10).map((post) => ({
    slug: post.slug,
  }))
}

すべてのパスを最初にアクセスされたときに静的にレンダリングするには、空の配列を返す(ビルド時にパスはレンダリングされない)か、export const dynamic = 'force-static'を使用します。

app/blog/[slug]/page.js
export async function generateStaticParams() {
  return []
}

知っておくと良いこと:generateStaticParamsからは、空であっても配列を返す必要があります。それ以外の場合、ルートは動的にレンダリングされます。

app/changelog/[slug]/page.js
export const dynamic = 'force-static'

リクエスト時にキャッシュを無効化するには、ルートセグメントにexport const dynamicParams = falseオプションを追加します。この構成オプションが使用されると、generateStaticParamsによって提供されるパスのみが提供され、他のルートは404になるか、マッチします(キャッチオールルートの場合)。

React cache関数

Reactのcache関数を使用すると、関数の戻り値をメモ化でき、同じ関数を複数回呼び出しても1回だけ実行されます。

GETまたはHEADメソッドを使用するfetchリクエストは自動的にメモ化されるため、React cacheでラップする必要はありません。ただし、他のfetchメソッドの場合、または(ネストされたデータベース、CMS、またはGraphQLクライアントなど)本質的にリクエストをメモ化しないデータフェッチライブラリを使用する場合、cacheを使用してデータリクエストを手動でメモ化できます。

utils/get-item.ts
import { cache } from 'react'
import db from '@/lib/db'
 
export const getItem = cache(async (id: string) => {
  const item = await db.item.findUnique({ id })
  return item
})