このページは、Next.jsのrevalidateTagとrevalidatePath、updateTagに関する整理メモである。
前提として押さえておきたい情報
そもそもrevalidateは、Webに昔からある概念である。 詳細を深掘りすると、Cache-Control ヘッダーやキャッシュの議論にも行き着く。
(HTTP)キャッシュ
リクエストとレスポンスを保存する仕組み。過去のやりとりを保存しておくことで、再度同じ条件のリクエストをした時に、保存したレスポンスの内容を再利用(または再検証)して、表示の高速化や通信量削減・サーバ負荷軽減などを行う仕組み。
具体的には、
- リクエスト情報をキーにし、対応するレスポンスを保存する
- ブラウザキャッシュであれば、ユーザーのPC内 > 各ブラウザ指定のディスクなどに保存される
- キャッシュにもいくつか種類があり、それぞれ仕様が異なる(共有/プライベートなど)
- そのレスポンスがキャッシュ可能かどうかも関係ある
- 後述するCache-Controlなども関係する
Cache-Control ヘッダー
ブラウザーや共有キャッシュ(プロキシーや CDN など)において、HTTPキャッシュを制御する仕組み。
Cache-control: max-age=180, publicのように、Cache-Control: <ディレクティブ>, <ディレクティブ>, ...のような形で書かれる。
リクエスト側・レスポンス側それぞれで使えるディレクティブが決まっている。
no-storeでキャッシュ保存しないようにしたり、max-ageとmust-revalidateなどで時間(キャッシュの鮮度)的に検証したり、文字通りキャッシュをコントロールするための指示を司っている。
上記に示した通り、このCache-Controlで使用できるディレクティブの中には、*-revalidate のようなものがある。ここでは詳細には書かないが、これらはいわゆる再検証を意味する。must-revalidateであれば、max-ageとともに併用され、キャッシュの時間的鮮度に応じて再検証を必須化する(再検証しないと再利用不可)。stale-while-revalidateであれば、キャッシュが古くなって再検証が必要な場合でも、設定した期間分は古いキャッシュを再利用できる。
このように、revalidateは再検証および古いキャッシュの扱い(再利用・破棄)に関連する概念である。
Next.jsのISR
ISRとは、Next.jsが提唱したIncremental Static Regenerationの略である。ここでは端的に、SSGやSSRのデメリットを解決できる可能性がある仕組みとして扱う。
たとえばSSGでは、基本的にプロジェクト全体を再ビルドすることでHTMLファイルなどを生成する。WebhookによるSSGワークフローであれば、Webhook受信後にプロジェクト全体を再ビルドし、CDNなどへキャッシュされた成果物を配信することで、ブラウザ描画に必要なファイルを届ける。
しかし、プロジェクトの規模が肥大化するほど、プロジェクト全体の再ビルドには時間がかかり、サーバー負荷も高まる可能性がある。
SSRは、パーソナライズ画面やリアルタイム描画が必要な場合に用いられる。これも非常に便利な仕組みだが、リクエスト数によってはサーバー負荷が膨大になる。
その上で、既存のレンダリング(SSG/SSRなど)のデメリットを、場合によっては代替できる仕組みとしてISRがある。基本的な仕組みは、キャッシュ + CDN + トリガー(Webhookや時間など)で構成されているものであり、トリガーを起点に、キャッシュうまく保存・再利用・再検証することで、CDNからいつでも素早くユーザーにコンテンツをお届けすると言うもの。
感じ方には個人差があるが、どちらかというと多少の遅延が許される静的寄りのプロジェクトを、効率よく運用する仕組みとしてISRは非常に便利だと感じる(よくWebhookを用いてOn-demand ISRを実装する)。
そしてISRには、大きく分けて以下の2つがある。
- Time-based revalidation
- On-demand revalidation
ざっくり説明すると、Time-basedは時間経過をトリガーに再検証を促すISRであり、On-demandは何かしらのイベント(たとえばCMSからのWebhook通知)をトリガーに再検証を促すISRである。
今回整理する revalidateTag と revalidatePath は、後者のOn-demand revalidation実装時に使用できるNext.js APIである。
revalidatePath
revalidatePathは、ルートごとにキャッシュを無効化する仕組みである。
Server Action1およびRoute Handler2で呼び出せる(基本的にサーバーで処理されるため、クライアントでは使えない)。
Pathの名の通り、以下のようなものを無効化できる。
- ページ(指定ページのキャッシュ)
- レイアウト(レイアウト配下のネストされたレイアウト/ページ)
- Route Handler2(Handler内で参照されたデータなど)
基本的な構文は以下の通り。
import { revalidatePath } from 'next/cache';
revalidatePath(path: string, type?: 'page' | 'layout'): void;
revalidatePath() のシグネチャは以下の通り。
path には、具体のURL(例: /posts/1)やルートパターン(例: /posts/[id])を指定する。
type には page または layout を指定する。動的セグメント(xxx/[slug]など)を含むパターン指定時は必須であり、それ以外ではオプションである。
個人的には、以下のようにRoute Handler2でCMSなどのWebhookをトリガーとして、ページや特定URLのキャッシュ無効化・再検証に使うことが多い。 以下のような場合、指定したパスは次回訪問時にキャッシュ再検証される。
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/post-1')
revalidateTag
revalidateTagは、キャッシュタグが付与されたコンテンツのキャッシュを無効化する仕組みである。
Server Action1およびRoute Handler2でのみ呼び出せる点は、revalidatePathと同様である(基本的にサーバーで処理されるため、クライアントでは使えない)。
Tagという名前の通り、以下のようにタグ付けされているモノのキャッシュを無効化できる。
fetch(..., { next: { tags: [...] } })でタグ付けしたData Cache'use cache'+cacheTag(...)でタグ付けしたキャッシュ
基本的な構文は以下の通り。
import { revalidateTag } from 'next/cache';
revalidateTag(tag: string, profile: string | { expire?: number }): void;
revalidateTag() のシグネチャは以下の通り。
tag には対象タグを指定する。
profile には、max(stale-while-revalidate)またはカスタムのcacheLifeプロファイル名、即時失効のための { expire: 0 } などを指定できる。
実運用では、データ取得側でTagを付与し、更新イベント側(Webhook受信用Route Handler2など)で revalidateTag を呼ぶ構成にすることが多い。
const posts = await fetch('https://api.example.com/posts', {
next: { tags: ['posts'] },
}).then((res) => res.json());
import { revalidateTag } from 'next/cache';
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
const body = await request.json();
if (body.secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ ok: false }, { status: 401 });
}
revalidateTag('posts', 'max');
return NextResponse.json({ ok: true });
}
このようにしておくと、CMS更新をトリガーに posts タグ付きキャッシュを再検証対象にできる。profile: 'max' を使えば stale-while-revalidate で更新されるため、即時全体再計算を避けつつ整合性を保ちやすい。
updateTag
revalidatePath・revalidateTag以外にも、updateTag というAPIも存在する。
updateTag は、タグ付きキャッシュを即時失効させるAPIである。revalidateTag('tag', 'max') と異なり stale を返さず、次の読み取りでfreshデータ取得を待つのが特徴である。
公式ブログのNext.js v16 リリース(2025年10月21日公開)で updateTag()(new)として追加が明記されており、利用前提はNext.js v16以降である。
基本的な構文は以下の通り。
import { updateTag } from 'next/cache';
updateTag(tag: string): void;
updateTag()はServer Actions1でのみ呼び出せる(Route Handler2内で使用しようとするとエラーになる)。
これにより、「更新した本人には直後に必ず新しいデータを見せたい」というread-your-own-writesの要件を満たしやすくなる。
read-your-own-writes とは、自分が書き込んだ更新結果を直後の読み取りで必ず自分が観測できる一貫性の考え方である。たとえば投稿作成直後に一覧へ戻った時、作成した投稿がすぐ表示される状態を担保したい場合に重要になる。
具体例としては、投稿作成や編集のServer Action1でDB更新直後にupdateTagを呼ぶケースが分かりやすい。
'use server';
import { updateTag } from 'next/cache';
import { redirect } from 'next/navigation';
import { db } from '@/lib/db';
export async function createPostAction(formData: FormData) {
const title = String(formData.get('title') ?? '');
const post = await db.post.create({ data: { title } });
updateTag('posts');
updateTag(`post-${post.id}`);
redirect(`/posts/${post.id}`);
}
このようにしておくと、更新直後の一覧・詳細画面で古いキャッシュを返しにくくなる。
3つそれぞれの比較
| API | 一言概要 | 無効化スコープ | 対象キャッシュ | 呼び出せる場所 | 次回表示時の挙動 | 向いているユースケース |
|---|---|---|---|---|---|---|
revalidatePath | パス単位で再検証 | 指定ページ/レイアウト/Route Handler2パス | 主にData Cache + その再レンダリング結果 | Server Functions3 / Route Handlers2 | Pathに対して次回訪問で再検証(Server Function時は表示中UIへ即時反映あり) | 「このページ群だけ」更新したい時 |
revalidateTag | タグ単位で再検証 | 同じタグを使う全ページ横断 | タグ付きData Cache | Server Functions3 / Route Handlers2 | profile: 'max' なら stale-while-revalidate | 共有データを複数画面で使う時、Webhook連携 |
updateTag | タグ単位で即時失効 | 同じタグを使う全ページ横断 | タグ付きData Cache | Server Actions1のみ | 次リクエストはfresh取得を待つ(staleを返さない) | read-your-own-writesを厳密に担保したい時 |
revalidatePathとrevalidateTagの違い
- 粒度が違う
revalidatePath: ルート(URL/ルートパターン)起点revalidateTag: データタグ起点
- 影響範囲が違う
revalidatePath: 指定したパスに紐づく表示更新が中心revalidateTag: 同タグを使う別ページにも横断的に影響
- 設計の使い分け
- ページ/レイアウト単位で明確に更新したいなら
revalidatePath - データソース単位で複数画面をまとめて整合させたいなら
revalidateTag
- ページ/レイアウト単位で明確に更新したいなら
revalidateTagとupdateTagの違い
- 更新ポリシーが違う
revalidateTag(tag, 'max'): stale-while-revalidate(ユーザーに古い内容を返しつつ裏で更新)updateTag(tag): 即時失効(次リクエストはfresh取得を待つ)
- 呼び出し可能コンテキストが違う
- 使い分けの基準
- 多少の遅延許容・負荷平準化重視なら
revalidateTag('tag', 'max') - 「更新した本人には直後に必ず新しい結果を見せる」なら
updateTag
- 多少の遅延許容・負荷平準化重視なら
参考資料
- Caching and Revalidating | Next.js公式Docs
- cacheLife | Next.js公式Docs
- revalidateTag | Next.js公式Docs
- updateTag | Next.js公式Docs
- Next.js 16 | Next.js公式ブログ
- Cache-Control ヘッダー | MDN
- キャッシュ | MDN
- キャッシュディレクティブ(Cache-Control) | MDN
Footnotes
-
Server Actionとは: https://nextjs.org/docs/app/getting-started/updating-data
-
Route Handlerとは: https://nextjs.org/docs/app/getting-started/route-handlers
-
Server Functionsとは(
'use server'で定義し、サーバー実行関数を使用できる。内部の実態は、Reactの機能): https://nextjs.org/docs/app/api-reference/directives/use-server#server-functions