この記事の要点
- キャッシュの寿命は
cacheLifeで決める。stale・revalidate・expireの 3 つの時間で構成される。 - 時間ではなく出来事で捨てたい場合は
cacheTagで目印を付け、更新時にそのタグを指定して無効化する。 revalidateTagは「古いものを見せつつ裏で更新」、updateTagは「今すぐ反映」。用途が違う。- バージョン 16 の
revalidateTagは第 2 引数が必須になった。1 引数の書き方は型エラーになる。 refreshはクライアント側のルーターを更新するだけで、タグ付きデータの再取得は行わない。
キャッシュを置いた瞬間から「いつ捨てるか」という問題が生まれます。長すぎれば古い情報が出続け、短すぎればキャッシュの意味がありません。Next.js はこれを「時間で切る」と「出来事で切る」の 2 系統で扱います。この記事では両者の使い分けと、バージョン 16 で追加・変更された API を整理します。
1時間で切る — cacheLife の 3 つの値
cacheLife は 'use cache' のスコープ内で呼び、そのキャッシュの寿命を決めます。指定するのは 3 つの時間です。
| プロパティ | 意味 | 効く場所 |
|---|---|---|
stale | クライアントがサーバーに問い合わせずキャッシュを使える時間 | ブラウザ側のルーター |
revalidate | この時間を過ぎた後の最初のリクエストで、裏側での作り直しが始まる | サーバー |
expire | この時間アクセスが無いと、次のリクエストは新しい内容ができるまで待つ | サーバー |
この 3 つを毎回考えるのは大変なので、名前付きのプリセットが用意されています。
| プロファイル | 想定する用途 | revalidate | expire |
|---|---|---|---|
seconds | 株価・スコアなどのリアルタイム値 | 1 秒 | 1 分 |
minutes | ニュース・フィード | 1 分 | 1 時間 |
hours | 在庫・天気など日に数回更新 | 1 時間 | 1 日 |
days | ブログ記事 | 1 日 | 1 週間 |
weeks | 週次のコンテンツ | 1 週間 | 30 日 |
max | 規約ページなど、ほぼ変わらないもの | 30 日 | 1 年 |
default | 指定しなかった場合に適用される | 15 分 | 無期限 |
// app/blog/[slug]/page.tsx
import { cacheLife } from 'next/cache'
export default async function BlogPost() {
'use cache'
cacheLife('days') // ブログ記事は日次更新
const post = await fetchBlogPost()
return <article>{post.content}</article>
}
プリセットが合わない場合は、next.config.ts で独自の名前を定義するか、その場でオブジェクトを渡します。省略したプロパティは default から引き継がれます。
// next.config.ts
const nextConfig = {
cacheComponents: true,
cacheLife: {
editorial: {
stale: 600, // 10 分
revalidate: 3600, // 1 時間
expire: 86400, // 1 日
},
},
}
export default nextConfig
cacheLife は毎回書くことが推奨されています。省略しても動きますが、入れ子になったキャッシュがあると、外側の寿命が内側に引っぱられて短くなることがあり、追いにくくなるためです。
2出来事で切る — cacheTag
「記事を編集したら、その記事のキャッシュだけを捨てたい」という要求は時間では表現できません。この場合はキャッシュにタグを付けます。
import { cacheLife, cacheTag } from 'next/cache'
async function getPost(slug: string) {
'use cache'
cacheLife('days')
cacheTag(`post-${slug}`) // このエントリの目印
return await fetchPost(slug)
}
あとは更新処理の中で、そのタグを指定して無効化します。タグは複数付けられるので、「この記事」と「記事一覧」の両方を同時に狙うこともできます。
3revalidateTag と updateTag の違い
ここがバージョン 16 で最も間違えやすい部分です。似た名前の 2 つは、目的がはっきり分かれています。
revalidateTag はバージョン 16 で第 2 引数が必須になりました。ここには cacheLife のプロファイル名を渡します。
// 旧: revalidateTag('posts')
revalidateTag('posts', 'max')
updateTag は Server Actions の中でのみ使える API で、キャッシュを失効させたうえで同じリクエストの中で作り直します。ユーザーが自分の変更をすぐ確認できる、いわゆる read-your-writes の挙動になります。
// app/actions.ts
'use server'
import { updateTag } from 'next/cache'
export async function updateUserProfile(userId: string, profile: Profile) {
await db.users.update(userId, profile)
updateTag(`user-${userId}`) // 即座に反映される
}
4revalidatePath と refresh
タグを付けていない場合や、URL 単位でまとめて捨てたい場合は revalidatePath が使えます。これは内部的にはタグ機構の上に乗った便利関数で、そのパス用の特別なタグを無効化しています。
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
// データを更新する処理
revalidatePath('/posts')
}
もう一つ、refresh という API があります。これはクライアント側のルーターを更新するだけで、タグ付きキャッシュの再取得は行いません。ヘッダーの通知件数を更新したい、といった軽い用途向けです。
特定データを狙うなら
cacheTag + revalidateTag / updateTag。画面まるごとなら revalidatePath。表示の再取得だけなら refresh。refresh を呼んだのに古い値が出続ける、という相談は多い。タグ付きデータには効かないので、updateTag を使う場面である可能性が高い。5寿命の短さが描画に与える影響
寿命の指定は「いつ作り直すか」だけでなく、「事前生成に含められるかどうか」にも影響します。
revalidateが 0、またはexpireが 5 分未満 → 事前生成から外れ、リクエスト時に解決されるstaleが 30 秒未満 → 先読みしても届く前に期限切れになるため、事前生成から外れる
プリセットの中では seconds だけがこの条件に当たります。リアルタイム性の高い部分を seconds にする場合は、Suspense で包んでフォールバックを用意しておくのが自然な構成になります。
6つまずきやすいところ
revalidateTag('posts')が型エラーになる:バージョン 16 では第 2 引数が必須です。- 更新したのに画面が変わらない:
revalidateTagは古い内容を見せたまま裏で更新します。即時反映が必要ならupdateTagです。 - 複数インスタンスで反映されない:既定ではタグの無効化は呼ばれたインスタンスにしか効きません。複数台構成では共有ストアとタグ同期の仕組みが要ります(本番ビルドとセルフホスト)。
- 入れ子のキャッシュで寿命が縮む:外側に
cacheLifeを明示していないと、内側の短い寿命に引っぱられます。外側にも必ず書きます。
読み取り側の設計はここまでです。次は書き込み、つまりフォーム送信とデータ更新に進みます。
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09