何をする関数か
revalidateTag は fetch リクエストに付けたタグを指定し、そのタグを持つすべてのキャッシュを即時無効化する関数です。Server Action や Route Handler でデータを更新したあとに呼びます。
"use server";
import { revalidateTag } from "next/cache";
export async function updatePost(id: string) {
await db.post.update({ where: { id }, data: { ... } });
revalidateTag("posts"); // "posts" タグを持つ全キャッシュを無効化
revalidateTag(`post-${id}`); // 特定投稿のキャッシュだけ無効化
}
タグ設計が前提になる
revalidateTag が有効になるには、fetch 側で next: { tags: [...] } を設定しておく必要があります。タグなしの fetch は revalidateTag の対象外です。
// データ取得側: タグを付けておく
const posts = await fetch("/api/posts", {
next: { tags: ["posts"] },
});
const post = await fetch(`/api/posts/${id}`, {
next: { tags: ["posts", `post-${id}`] },
});
// 更新側: タグで無効化
revalidateTag("posts"); // 一覧系をまとめて無効化
revalidateTag(`post-${id}`); // 特定投稿のみ無効化
revalidatePath との使い分け
revalidatePath | revalidateTag | |
|---|---|---|
| 無効化の単位 | URL パス | データのタグ |
| 複数ページまたぎ | パスを個別に列挙 | タグ 1 つで一括 |
| 前提条件 | 特になし | fetch 側のタグ設計が必要 |
| 向くケース | 更新対象ページが明確で少ない | 1 件の更新が複数ルートに影響する |
1 件の投稿更新が一覧・詳細・カテゴリページなど複数ルートに影響する場合、revalidatePath では各パスを列挙する必要があります。revalidateTag なら "posts" タグ 1 つで一括無効化できます。
よくあるつまずき
タグを付けていない
revalidateTag("posts") を呼んでも、fetch 側に tags: ["posts"] が付いていないと何も無効化されません。タグは取得側と更新側の両方で設計する必要があります。
タグの粒度が荒すぎる
// ❌ 何でも "all" にすると関係ないページまで再検証される
revalidateTag("all");
// ✅ データ種別でタグを分ける
revalidateTag("posts");
revalidateTag("users");
タグの粒度が細かすぎる
レコードごとに post-1, post-2, ... と個別タグを付けると、更新時に revalidateTag の呼び出しが増えて管理が複雑になります。一覧と詳細で共通のタグ("posts")を持ちつつ、詳細専用タグ(`post-${id}`)を追加するハイブリッド設計が実用的です。
注意点
- Server Action・Route Handler の中でのみ呼べる(クライアントコンポーネントでは使えない)
fetchを使わない Prisma 直接クエリなどにはtagsオプションが存在しない。そのような場合はrevalidatePathを使う- タグ名は文字列の一致で管理されるため、タイポに気づきにくい。定数として管理すると安全
// タグ名を定数管理する例
export const CACHE_TAGS = {
posts: "posts",
post: (id: string) => `post-${id}`,
} as const;
// 取得側
fetch("/api/posts", { next: { tags: [CACHE_TAGS.posts] } });
// 更新側
revalidateTag(CACHE_TAGS.posts);
revalidatePath との違いやキャッシュ設計の全体像は → Next.js キャッシュ設計