---
title: "Next.jsのキャッシュ｜16.4のuse cache・revalidateTagの使い分けとCDNで効かない原因"
url: "https://www.issoh.co.jp/tech/details/2282/"
published: 2024-05-27
updated: 2026-10-12
categories: ["Next.js"]
publisher: "株式会社一創"
---

# Next.jsのキャッシュ｜16.4のuse cache・revalidateTagの使い分けとCDNで効かない原因

Next.jsのキャッシュは、バージョン15と16で既定の挙動が変わり、2026年10月6日公開の16.4で推奨の書き方も決まりました。16.4では、`use cache`で必要な箇所だけをキャッシュするCache Componentsが「すべてのNext.jsアプリに推奨する方式」とされ、`create-next-app`で作る新規アプリでは最初から有効になっています。「App Routerは既定でキャッシュする」という13〜14当時の解説は、現在の仕様と違います。この記事では16.4.0を基準に、保存先・再検証API・効かないときの切り分けを、`next build`と`next start`で確かめた結果を交えて整理します。

## まとめ：Next.jsのキャッシュで押さえる4点

- **方式**：新規アプリはCache Components（`cacheComponents: true`と`partialPrefetching: true`）で書く。データ取得の結果は`use cache`を付けた関数・コンポーネントだけがキャッシュされ、未キャッシュの取得やCookieなどリクエスト依存の部分はリクエスト時に実行される。
- **寿命**：`use cache`には寿命を明確にするため`cacheLife`を明示する（省略も仕様上は可能）。省略すると`default`（サーバー側の再検証間隔15分）が適用される。15分たつと、その後のアクセスを契機に作り直される。
- **無効化**：操作した本人にすぐ見せるならServer Action内の`updateTag`、多少遅れてよいなら`revalidateTag(tag, 'max')`。
- **デプロイ**：`use cache`のエントリはキャッシュキーにビルドID（設定時は`deploymentId`）を含むため、そのIDが変わると以前のエントリは使われなくなる。デプロイ後に古い画面が出るなら、まずCDNとブラウザのHTTPキャッシュを疑う。

なお本稿が扱うのは実行時のキャッシュです。ビルドを速くするTurbopackのディスクキャッシュは別物で、[Next.js 16.3とは？Turbopack永続キャッシュとInstant Navigationsなど新機能を実装者目線で解説](/tech/details/15608/)で扱っています。

## キャッシュの保存先と旧4分類の対応

Next.jsの「キャッシュ」は、保存場所も寿命も異なる複数の層の総称です。キャッシュされた関数の出力はRSCペイロードにシリアライズされ、HTMLとして置かれるか、サーバーに残るか、ブラウザへ送られるかが違うだけです（[公式のCachingガイド](https://nextjs.org/docs/app/getting-started/caching)）。ペイロードの中身は[RSC Payload（RSCペイロード）とは？中身の読み方と取得手順](/tech/details/4526/)で解説しています。

| 層                        | 保存先          | 寿命の決め方               | 13〜14の呼び名        |
| ------------------------ | ------------ | -------------------- | ---------------- |
| プリレンダーHTML・ISR           | ディスク＋メモリ50MB | revalidate / expire  | Full Route Cache |
| fetch・unstable\_cacheの結果 | ディスク＋メモリ50MB | revalidate           | Data Cache       |
| use cacheの結果             | 各インスタンスのメモリ  | cacheLife            | （16で新設）          |
| 共有キャッシュ                  | Redis等の外部ストア | cacheLife・revalidate | （なし）             |
| クライアントキャッシュ              | ブラウザのメモリ     | stale（最低30秒）         | Router Cache     |
| HTTPキャッシュ                | CDN・ブラウザ     | Cache-Control        | （Next.jsの外）      |

旧4分類のうちRequest Memoizationは、1回のレンダリング内で同じ`fetch`をまとめるだけでレンダリングをまたいで残らないため、表には入れていません。

### サーバー側：インスタンスごとに分かれる2つの保存先

サーバー側には仕組みの違う保存先が2つあります。ページの生成結果・ISR・`fetch`と`unstable_cache`の結果を持つ従来のサーバーキャッシュは、各インスタンスのディスクとメモリ（`cacheMaxMemorySize`の既定値50MB）に置かれます（[Self-Hostingガイド](https://nextjs.org/docs/app/guides/self-hosting)）。一方、`use cache`の既定ハンドラはメモリ上のLRUだけを使い、サーバーレスではインスタンスが使い捨てられるのでリクエストをまたいでほぼ残りません。Kubernetesのように複数インスタンスを並べると、どちらもPodごとに別々のキャッシュになります。

共有したい場合の設定も別々です。`use cache`は`use cache: remote`か`cacheHandlers`（複数形）で外部ストアのハンドラを指定します。従来のサーバーキャッシュは`cacheHandler`（単数形）を指定し、`cacheMaxMemorySize: 0`でインスタンスごとのメモリキャッシュを止めます。

もう1つの落とし穴が無効化の伝わり方です。`revalidateTag`は既定では呼び出したインスタンスのキャッシュしか消しません。他のインスタンスへ伝えるには、共有ストアに無効化の記録を置きます。`use cache`用の`cacheHandlers`では`updateTags()`（無効化を共有ストアへ書く）と`refreshTags()`（リクエスト前に読みに行く）の両方を、従来方式の`cacheHandler`では`revalidateTag()`メソッドを実装します（[How Revalidation Works](https://nextjs.org/docs/app/guides/how-revalidation-works)）。

### ブラウザ側：最低30秒のクライアントキャッシュ

クライアントルーターは、プリフェッチやナビゲーションで受け取ったRSCペイロードをブラウザのメモリに保持します。寿命は`cacheLife`の`stale`値で、サーバーは`x-nextjs-stale-time`レスポンスヘッダーで伝えます。`cacheLife('hours')`のページを実測すると`x-nextjs-stale-time: 300`が返りました。ここには最低30秒の下限があり、それより短くはできません。Server Actionから再検証系のAPIを呼ぶと、stale時間に関係なくクライアントキャッシュは即座にクリアされます。

## バージョンごとに変わった既定値

解説記事を読むときは、どの版を前提にしているかを先に確かめてください。既定値が版ごとに変わっているためです。公式リリース記事の日付は15が2024年10月21日、16が2025年10月21日、16.3が2026年8月3日、16.4が2026年10月6日です。

| 対象                 | 13〜14    | 15     | 16.0〜16.3 | 16.4        |
| ------------------ | -------- | ------ | --------- | ----------- |
| fetch              | 既定でキャッシュ | 非キャッシュ | 非キャッシュ    | 非キャッシュ      |
| GET Route Handler  | 既定でキャッシュ | 非キャッシュ | 非キャッシュ    | 非キャッシュ      |
| staleTimes.dynamic | 30秒      | 0秒     | 0秒        | 0秒          |
| cacheComponents    | なし       | 実験的    | 任意で有効化    | 推奨・新規は既定で有効 |
| partialPrefetching | なし       | なし     | 16.3で追加   | 推奨構成で有効     |

15での変更は、`fetch`・GET Route Handler・クライアントのルーターキャッシュを「キャッシュする」から「しない」へ倒すものでした（[Next.js 15のリリース記事](https://nextjs.org/blog/next-15)）。16では`experimental.dynamicIO`と`experimental.ppr`が`cacheComponents`にまとめられました。Next.js本体の`cacheComponents`の既定値は16.4でも`false`なので、既存アプリを16.4へ上げただけでは有効になりません。16.4の[リリース記事](https://nextjs.org/blog/next-16-4)は、次のメジャーである17でCache Componentsを既定にすると予告しています。版ごとの変更点とアップデート手順は[Next.js 16の最新バージョンは16.3｜リリース履歴・LTS方針・アップデート手順](/tech/details/9596/)にまとめています。

## Cache Componentsを有効にする設定

既存アプリで有効にするには`next.config.ts`に2つのフラグを立てます。`create-next-app@16.4.0`はこの2行を既定で書き込みます。

```
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
}

export default nextConfig
```

`partialPrefetching`を書かずに`next build`すると、「`cacheComponents` is enabled without a corresponding `partialPrefetching` option」という警告が出ます。`partialPrefetching`は16.3.0で追加された設定で、`false`にするのはPartial Prefetchingより前にCache Componentsを導入済みのアプリを移行している途中だけです。有効化するとPartial Prerendering（PPR）が既定になり、静的なシェルを先に返してリクエスト依存の部分だけを後から流します。Node.jsランタイムが必須なので、`export const runtime = 'edge'`を残しているルートは移行が必要です。

## use cacheによるデータとUIのキャッシュ

`use cache`はファイル先頭、コンポーネント本体の先頭、関数本体の先頭のいずれにも置けます。対象はasync関数に限られます。キャッシュキーはビルドID、関数の位置と署名、引数から作られ、外側のスコープから参照した変数も自動的に引数としてキーに入ります。

### 静的UI・キャッシュ・ストリーミングを組み合わせたページ実装

次の例は`app/blog/page.tsx`に置く想定で、`@/lib/db`はアプリ側で用意するDBアクセス層です。見出しは静的、記事一覧は1時間を過ぎた後のアクセスを契機に背後で作り直し、Cookieを読むテーマ表示はリクエスト時にストリーミングします。

```
import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { cacheLife, cacheTag } from 'next/cache'
import { db } from '@/lib/db'

export default function BlogPage() {
  return (
    <>
      <h1>ブログ</h1>
      <PostList />
      <Suspense fallback={<p>読み込み中…</p>}>
        <Theme />
      </Suspense>
    </>
  )
}

async function PostList() {
  'use cache'
  cacheLife('hours')
  cacheTag('posts')
  const posts = await db.posts.list()
  return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>
}

async function Theme() {
  const theme = (await cookies()).get('theme')?.value ?? 'light'
  return <p>テーマ: {theme}</p>
}
```

next@16.4.0でビルドすると、このルートは`◐ /blog 1h 1d`（Partial Prerender、Revalidate 1時間、Expire 1日）と表示されました。Cookieを読んでもルート全体が動的レンダリングに倒れることはなく、見出しと記事一覧は静的シェルに入ります。`cookies()`や`headers()`を`use cache`の内側で読むことはできないので、外で値を取り出して引数で渡します。

### cacheLifeのプリセット値と短命キャッシュの扱い

`cacheLife`は`stale`（クライアントが確認なしで使える時間）、`revalidate`（サーバーが背後で作り直すまでの時間）、`expire`（アクセスが無いまま経過したら同期再生成に切り替わる時間）の3つを持ちます。next@16.4.0の実装（`dist/server/config-shared.js`）の値は次のとおりで、[cacheLifeのリファレンス](https://nextjs.org/docs/app/api-reference/functions/cacheLife)の表とも一致します。

| プロファイル  | stale | revalidate | expire |
| ------- | ----- | ---------- | ------ |
| default | 5分    | 15分        | 期限なし   |
| seconds | 30秒   | 1秒         | 1分     |
| minutes | 5分    | 1分         | 1時間    |
| hours   | 5分    | 1時間        | 1日     |
| days    | 5分    | 1日         | 1週間    |
| weeks   | 5分    | 1週間        | 30日    |
| max     | 5分    | 30日        | 1年     |

寿命が短すぎるキャッシュはプリレンダーから外れます。`revalidate`が0か`expire`が5分未満なら、リクエスト時に解決される「動的な穴」になり、プリセットでは`seconds`だけが該当します。`stale`が30秒以上5分未満なら、プリレンダーには入りますが、プリフェッチで配るApp Shellからは外れます。入れ子にも注意が要ります。`cacheLife`を書いていない外側の`use cache`が短命キャッシュを含むと、外側まで短命化するのを防ぐためにビルドがエラーで止まります。外側に`cacheLife`を明示すれば解決します。

### use cache・private・remoteの選び分け

| ディレクティブ            | サーバー保存     | cookies等 | 向く用途        |
| ------------------ | ---------- | -------- | ----------- |
| use cache          | インスタンスのメモリ | 不可       | 全員共通のデータ    |
| use cache: remote  | 共有ハンドラ     | 不可       | ヒット率が高い重い処理 |
| use cache: private | しない        | 可        | ユーザー固有の表示   |

remoteは毎回ネットワーク往復が入るので、ヒット率が高いときしか元が取れません。privateの結果はブラウザのメモリにだけ残り、再読み込みで消えます。まずはCookieの値を外で読んで`use cache`の引数に渡す形を試し、書けないときだけprivateを使います。

### ensureStaticによる静的レンダリングの保証

16.4で追加された`export const ensureStatic = 'navigation'`をページやレイアウトに書くと、そのルートに動的な部分が紛れ込んだ時点でビルドが失敗します。上の`/blog`に付けて試すと、Cookieを読む`Theme`のせいで`Next.js encountered uncached or runtime data on a route that must be fully static.`というエラーで止まりました。値は`'shell'`・`'prefetch'`・`'navigation'`の順に厳しくなります。

## 再検証APIの使い分け

16では再検証APIの役割が整理されました。`fetch`の`next.tags`で付けたタグにも`cacheTag`で付けたタグにも同じように効き、`cacheComponents`の有無を問わず使えます。

| API                               | 呼べる場所                       | 次の読み取り       | 使う場面        |
| --------------------------------- | --------------------------- | ------------ | ----------- |
| revalidateTag(tag, ‘max’)         | Server Action・Route Handler | 旧データを返し背後で更新 | Webhook・一覧  |
| revalidateTag(tag, { expire: 0 }) | Server Action・Route Handler | 新データを待つ      | 外部からの即時削除   |
| updateTag(tag)                    | Server Actionのみ             | 新データを待つ      | フォーム送信・設定変更 |
| revalidatePath(path)              | Server Action・Route Handler | パス単位で無効化     | タグ設計の無いルート  |
| refresh()                         | Server Actionのみ             | 未キャッシュ部分だけ更新 | 通知件数        |

```
'use server'

import { revalidateTag, updateTag, refresh } from 'next/cache'
import { db } from '@/lib/db'

type Profile = { name: string }

export async function publishPost(id: string) {
  await db.posts.publish(id)
  revalidateTag('posts', 'max')
}

export async function saveProfile(id: string, data: Profile) {
  // 認証・更新権限・入力値の検証はここか db 層で行う前提
  await db.users.update(id, data)
  updateTag(`user-${id}`)
}

export async function markAsRead(id: string) {
  await db.notifications.markAsRead(id)
  refresh()
}
```

判断の基準は「更新した本人にすぐ見せる必要があるか」です。フォーム送信のように本人が結果を確認する導線では、読み取り直しを保証する`updateTag`を選びます。記事一覧のように多少の遅れが許されるものは`revalidateTag`に`'max'`を渡し、閲覧者には旧データを即座に返しながら背後で作り直させます。仕組みは[stale-while-revalidateとは？Cache-ControlとSWRの再検証を解説](/tech/details/7774/)を参照してください。

第2引数は省略できません。`revalidateTag('posts')`と書いてビルドすると、16.4では`error TS2554: Expected 2 arguments, but got 1.`で型チェックが通りませんでした。型エラーを抑えれば動きますが、挙動は`{ expire: 0 }`と同じになります（[revalidateTagのリファレンス](https://nextjs.org/docs/app/api-reference/functions/revalidateTag)）。

## CDNのキャッシュ可否とHTML・RSCのパージ対象

サーバーキャッシュを正しく書いても、手前のCDNが別の判断をすれば古い画面は出続けます。next@16.4.0を`next start`で起動して確かめたヘッダーが次の表です。

| ルート                      | Cache-Control                                           |
| ------------------------ | ------------------------------------------------------- |
| use cacheだけの静的ページ（hours） | s-maxage=3600, stale-while-revalidate=82800             |
| Suspenseで動的部分を含むページ      | private, no-cache, no-store, max-age=0, must-revalidate |
| /\_next/static配下のJS      | public, max-age=31536000, immutable                     |

静的ページの`stale-while-revalidate`は、`expire`（1日）から`revalidate`（1時間）を引いた値です。一方、動的な部分を1つでも含むPPRのページは、静的シェルがプリレンダー済みでもHTMLのレスポンスに`private, no-store`が付き、一般的なCDNはこれをキャッシュしません。公式は静的シェルをCDNから直接配信できると説明していますが、それはPPRに対応したデプロイ先やアダプターでシェルを分けて配る場合の話です。`next start`の前にCDNを置くだけの構成でページをCDNに載せたいなら、そのルートを完全に静的にします。

逆に、CDNがキャッシュしている静的ページでは`revalidateTag`や`revalidatePath`がCDNまで届きません。公式の[CDN Cachingガイド](https://nextjs.org/docs/app/guides/cdn-caching)も、CDNは`s-maxage`が切れるまで手元の複製を返し続けるので、再検証と同時にCDNのパージAPIを呼ぶよう案内しています。パージ対象にはHTMLとRSCの両方が要ります。RSCのリクエストはクエリ`_rsc`で区別され、実測では`rsc: 1`ヘッダーだけのリクエストに`?_rsc`付きURLへの`307`が返りました。クエリをキャッシュキーから外すCDNでは画面遷移が壊れます。CDN側の設定の考え方は[CDNとは？仕組み・キャッシュ制御からサービスの選び方まで実装目線で解説](/tech/details/13095/)を参照してください。

### Cache-Controlの全パス一括指定による長期キャッシュの危険

`headers()`で全パスに長いキャッシュ期間を付ける例を見かけますが、採用すべきではありません。

```
// 採用しないこと
module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
    }]
  },
}
```

この値は本来、ファイル名にハッシュを含む不変アセットにNext.jsが自動で付けるもので、公式はそのアセットについては上書きできないと書いています（[headersのリファレンス](https://nextjs.org/docs/app/api-reference/config/next-config-js/headers)）。問題は残りのパスです。15以降のNext.jsはカスタムの`Cache-Control`を既定値で上書きしなくなったため、HTMLページにも書いた値がそのまま出ます。`immutable`付きなので再検証も行われず、一度アクセスした人には何度デプロイしても最大1年間古いページが表示されます。手を入れるなら`/images/:path*`のように自分で管理する静的パスに限ります。

## cacheComponentsを使わない構成での書き方

既存アプリを16へ上げただけの場合、キャッシュは従来どおり個別に指定します。この構成でも`fetch`は既定でキャッシュされません（[Caching (Previous Model)](https://nextjs.org/docs/app/guides/caching-without-cache-components)）。

```
import { unstable_cache } from 'next/cache'
import { db } from '@/lib/db'

// fetch を明示的にキャッシュする
export async function getPosts() {
  const res = await fetch('https://api.example.com/posts', {
    cache: 'force-cache',
    next: { revalidate: 3600, tags: ['posts'] },
  })
  return res.json()
}

// fetch を使わない DB クエリをキャッシュする
export const getCachedUser = unstable_cache(
  async (id: string) => db.users.findUnique({ where: { id } }),
  ['user'],
  { tags: ['user'], revalidate: 3600 }
)
```

ルート単位なら、ページやレイアウトから`export const revalidate = 600`のように出します。ルート内で最も小さい`revalidate`がルート全体の間隔になります。レンダリング方式の選び方は[Next.jsのレンダリング方式｜SSG・ISR・SSR・CSRの違いとApp Routerでの選び方](/tech/details/3791/)で整理しています。

`unstable_cache`は公式に「16で`use cache`に置き換えられた」と明記されています。それでもこの構成を残す理由は1つで、`unstable_cache`と`fetch`のキャッシュは、保存先を維持する構成ならデプロイをまたいで再利用できるからです。セルフホストでコンテナを入れ替えるなら、永続ボリュームか外部ストアで保存先を残す必要があります。デプロイのたびに温め直すと外部APIの料金や負荷が問題になるデータだけ、この方式に残す判断はありえます。旧方式と新方式が混在する既存アプリの移行計画から相談したい場合は、[業務用・Webアプリ開発](https://www.issoh.co.jp/service/apps/business/)の支援も行っています。

## キャッシュが効かない・消えないときの切り分け

症状から原因の層を絞り込む手順です。上から順に確かめます。

- 開発サーバーで本番とキャッシュの挙動が違う → `next dev`ではページは常にオンデマンドで描画されますが、データ側のキャッシュは開発時にも働きます。ページのキャッシュは`next build`と`next start`で確かめます。
- デプロイ後も古い内容が出る → `use cache`はキーに使うID（ビルドIDか`deploymentId`）が変われば旧エントリを使いません。IDが変わったか、旧版のインスタンスに振り分けられていないか、デプロイをまたぐ`fetch`・`unstable_cache`のキャッシュ、CDNとブラウザのHTTPキャッシュを順に確かめます。
- revalidateTagを呼んだのに古い → まず第2引数を見ます。`'max'`なら、次のアクセスで作り直しが始まり、終わるまでのリクエストに旧データが返るのは正常な動作です。作り直しが終わっても古いなら、タグ名の一致、CDNが持っている複製、別インスタンスへの振り分けを確かめます。CDNはパージ、別インスタンスはキャッシュハンドラに共有ストアへの無効化の伝達を実装して直します。
- 本番でだけ`use cache`がエラーになる → キャッシュの内側（呼び出し先の関数を含む）で`cookies`や`headers`を読んでいます。動的なルートでは`next build`を通過し`next start`で落ちます。
- ビルドが50秒で止まる → `params`や`searchParams`、未キャッシュのデータを`use cache`の内側で待っています。値を先に取り出して引数で渡します。
- 戻る操作で古い画面が出る → クライアントキャッシュです。クライアントコンポーネントから`router.refresh()`を呼びます。ただしサーバー側のキャッシュは無効化されないので、そこが古ければタグやパスの再検証も要ります。`next/cache`の`refresh()`はServer Action専用の別APIです。

挙動を追うときは`NEXT_PRIVATE_DEBUG_CACHE=1`を付けて起動すると詳細ログが出ます。開発時はキャッシュされた関数のコンソール出力に`Cache`の接頭辞が付きます。ただしこれはキャッシュ済みの関数のログを再生した印で、接頭辞だけではヒットか新規実行かを判別できません。

## よくある質問

### Next.jsのキャッシュをクリアするにはどうすればよいですか？

層ごとに手段が違います。`use cache`の旧エントリは、キーに使うビルドID（設定時は`deploymentId`）が変われば使われなくなります。同じIDのまま再配備しただけでは消える保証はありません。特定のデータだけなら、Server Action内は`updateTag`、Route Handlerからは`revalidateTag`、ルート単位は`revalidatePath`です。CDNが持っている分はCDNのパージが別に要ります。

### Data Cacheはどこに保存されますか？

13〜14でData Cacheと呼ばれた`fetch`と`unstable_cache`の保存先は、セルフホストでは各インスタンスのディスクとメモリ（上限50MB）です。`use cache`のキャッシュはこれとは別の仕組みで、既定では各インスタンスのメモリだけに置かれます。複数のコンテナで共有するなら、従来方式は`cacheHandler`、`use cache`は`use cache: remote`か`cacheHandlers`でRedisなどの外部ストアに載せます。

### Lighthouseの「効率的なキャッシュ保存期間を使用する」はどう直しますか？

HTTPキャッシュの指摘です。ビルド出力のJavaScriptとCSSにはNext.jsが1年の`immutable`を自動で付けるので、指摘されるのは`public/`配下に自分で置いた画像やフォント、外部ドメインの配信物です。自サイトが配信するパスなら`headers()`か管理下のCDNでキャッシュ期間を付けます。外部ドメインの配信物は配信元で直すしかありません。同じURLのまま画像を差し替える運用なら、差し替えの頻度に合わせて期間を短めに決めます。

### SSRのページもキャッシュできますか？

できます。Cache Componentsでは、リクエスト時のデータを読む部分だけを`<Suspense>`で囲み、残りを`use cache`で事前レンダリングします。ただしHTMLのレスポンスには`private, no-store`が付くため、CDNでページ丸ごとをキャッシュする用途には向きません。

### ヘッドレスCMSの更新をすぐサイトへ反映するには？

キャッシュ関数に`cacheTag`でタグを付け、CMSのWebhookから呼ぶRoute Handlerで`revalidateTag('posts', 'max')`を実行します。Route Handlerでは`updateTag`が使えないので、次の閲覧から必ず新しい内容を出したいときは`revalidateTag('posts', { expire: 0 })`にします。下書きのプレビューにはDraft Modeを使います。その間はキャッシュが迂回されますが、有効化用のRoute Handlerと秘密トークンの検証は別に実装が要ります（[Draft Modeガイド](https://nextjs.org/docs/app/guides/draft-mode)）。

## 関連記事

- [Next.jsのレンダリング方式｜SSG・ISR・SSR・CSRの違いとApp Routerでの選び方](/tech/details/3791/)
- [Next.js 16の最新バージョンは16.3｜リリース履歴・LTS方針・アップデート手順](/tech/details/9596/)
- [stale-while-revalidateとは？Cache-ControlとSWRの再検証を解説](/tech/details/7774/)
- [Version Skew（バージョンスキュー）とは？原因とNext.js・Vercelでの対策を実測で解説](/tech/details/9400/)
- [RSC Payload（RSCペイロード）とは？中身の読み方と取得手順](/tech/details/4526/)

---

出典: [Next.jsのキャッシュ｜16.4のuse cache・revalidateTagの使い分けとCDNで効かない原因](<https://www.issoh.co.jp/tech/details/2282/>)（株式会社一創）
