Vercelのrewriteを使っていると、「昨日までは速かったのに、今日から急に古いレスポンスが返る」という現象に出会いますよね。2026年4月以降はexternal-origin rewriteの既定挙動が変わったので、旧来の前提で作った構成が崩れやすくなっています。この記事は、Vercel Cache-ControlとNext.js 16.2 rewrite キャッシュを実務で安全に運用したい人向けです。読むと、鮮度・コスト・不整合の3つを同時に管理できる実装テンプレートを、そのまま今日から使える状態で持ち帰れます。僕は福祉事業のIT全般を担当しつつAI×SaaS開発も並行しているので、運用現場でハマったポイントまで含めて共有します。
こんな方におすすめ
- Vercelのexternal-origin rewriteでキャッシュ挙動が読めず困っている
- Next.js 16.2でrewriteを組み直す予定がある
- 表示速度を上げたいが、更新反映の遅れは避けたい
- 本番で壊さないCache-Control設計テンプレートがほしい
この記事でわかること
- 2026年4月以降のVercel rewriteキャッシュ仕様の実務整理
- ブラウザ・他CDN・Vercelの3層ヘッダ分離テンプレート
- Next.js 16.2で安全にrewriteを適用する順番と実装コード
- 事故時の復旧Runbookと本番チェックリスト
公開前確認(2026年5月時点):Vercelのexternal-origin rewriteは、新規プロジェクトでは2026年4月6日以降、上流の Cache-Control / CDN-Cache-Control / Vercel-CDN-Cache-Control を既定で尊重します。既存プロジェクトはダッシュボード設定や x-vercel-enable-rewrite-caching の有無で挙動が分かれるため、必ず本番URLで実測してください。
2026年4月の変更点と、external-origin caching 2026で壊れる条件
最初に日付を固定します。Vercelは2026年3月30日のchangelogで、external-origin rewrite時に上流Cache-Controlを既定尊重する変更を発表し、新規プロジェクトでは2026年4月6日から適用されています。ここが大きな分岐点です。以前は「rewrite先は基本キャッシュされにくい前提」で設計していた人が多かったので、その設計のまま移行すると予期しないHITが増えます。
さらに混乱しやすいのが、Rewritesドキュメントに旧説明が一部残っている点です。つまり、プロジェクト作成時期とダッシュボード設定で挙動が分かれるので、ドキュメントだけで判断するとズレやすいです。まず「自分のプロジェクトはどのモードか」を確認することが最優先です。
| ケース | 挙動 | 最初に確認する項目 |
|---|---|---|
| 2026-04-06以降に作成した新規プロジェクト | 上流Cache-Controlを既定尊重 | 上流のTTLがそのまま効いていないか |
| 既存プロジェクト(未opt-in) | 旧挙動のままの可能性 | ダッシュボード設定と実測ヘッダ |
| 既存プロジェクト(opt-in済み) | 新既定相当で動作 | パス単位で例外が必要か |
| 特定パスだけ除外したい | ヘッダでopt-out可能 | x-vercel-enable-rewrite-caching: 0 |
- 確認1 – 本番で
curl -Iして、実際のTTLを見ます - 確認2 – 旧記事や社内Wikiの前提を2026年版に更新します
- 確認3 – external rewriteは必ずステージングで再検証します
Vercel Cache-Controlを3層で分離する設計テンプレート
次に設計です。ここはVercel公式の優先順位が軸になります。優先順位はVercel-CDN-Cache-Control > CDN-Cache-Control > Cache-Controlです。つまり、同じレスポンスで3つ返せば、ブラウザ・他CDN・Vercelを分離できます。イメージとしては、同じ荷物に「倉庫向け」「配送向け」「店頭向け」の3枚ラベルを貼る感じです。
おすすめは、ブラウザ短め・Vercel長めで分離する構成です。たとえば、ブラウザは10秒、他CDNは60秒、Vercelは3600秒という分け方です。これなら体感速度を確保しつつ、頻繁更新のページだけは短いTTLにできます。さらにVercel Functionsのレスポンスヘッダはnext.config.jsやvercel.jsonより優先されるので、最終判断はアプリ側で持つほうが事故が減ります。
Cache-Control: max-age=10
CDN-Cache-Control: max-age=60
Vercel-CDN-Cache-Control: max-age=3600
キャッシュされる条件も先に確認
- メソッド – GET/HEADが前提です
- ステータス – 200/404/410/301/302/307/308が対象です
- 除外条件 –
set-cookieやAuthorizationがあると外れやすいです - サイズ上限 – non-streaming 10MB、streaming 20MBです
「TTLだけ決めて終わり」にしないことが重要です。キャッシュ条件を知らないままだと、想定どおりに載っていないのに気づけず、コストだけ上がる可能性があります。
Next.js 16.2 rewrite キャッシュを壊さない適用順
Next.js側は順番を間違えると意図せず全体がプロキシ化されます。公式の適用順は、headers → redirects → beforeFiles → 静的ファイル → afterFiles → fallbackです。特に外部originへの退避をfallbackで使うときは、先にローカルの一致条件を絞っておくのが安全です。
そして2026年3月18日に出たNext.js 16.2は、開発サイクルがかなり速くなっています。next dev起動で最大約400%改善、描画は約50%改善、HTMLレンダリングも25〜60%改善の報告があります。つまり、rewriteの検証ループを回すコストが下がったので、設計を勘で決めるより小さく試すほうが得です。
- beforeFilesで明示的に許可 – APIなど明確な対象だけexternal rewriteします
- afterFilesで補完 – 静的アセットを食わないように後段に置きます
- fallbackは退避用 – 段階移行の受け皿として限定運用します
- trailingSlash整合 – 有効化時はsource/destination両方に末尾
/を合わせます
// next.config.js
async rewrites() {
return {
beforeFiles: [
{ source: '/api/:path*', destination: 'https://api.example.com/:path*' }
],
fallback: [
{ source: '/:path*', destination: 'https://legacy.example.com/:path*' }
]
}
}
「何をrewriteしないか」を先に決めると、事故率が一気に下がります。
実装テンプレート集: vercel.json・Route Handler・監視curl
ここからはそのまま貼って使える形です。まずはVercel側のrewrite定義です。新既定に合わせるなら、必要なパスだけ明示して、除外が必要なところだけx-vercel-enable-rewrite-caching: 0を当てる運用がわかりやすいです。
{
"rewrites": [
{ "source": "/api/:path*", "destination": "https://api.example.com/:path*" }
],
"headers": [
{
"source": "/api/live/:path*",
"headers": [
{ "key": "x-vercel-enable-rewrite-caching", "value": "0" }
]
}
]
}
次にRoute Handlerで3層ヘッダを返す例です。ここでTTLを役割分担しておくと、後の調整が最小変更で済みます。
// app/api/news/route.ts
export async function GET() {
const data = await fetch("https://upstream.example.com/news").then(r => r.json());
return Response.json(data, {
headers: {
"Cache-Control": "max-age=30",
"CDN-Cache-Control": "max-age=120",
"Vercel-CDN-Cache-Control": "max-age=1800"
}
});
}
最後に監視です。デプロイ後は最低でもこの3本を回します。ヘッダ監視をCIに入れるだけで、設定ドリフトにすぐ気づけます。
curl -sI https://your-app.com/api/news | grep -Ei "cache-control|cdn-cache-control|vercel-cdn-cache-control"
curl -sI https://your-app.com/api/news | grep -Ei "x-vercel-cache|age"
curl -sI "https://your-app.com/page?_rsc=1" | grep -Ei "vary|cache-control"
- 運用メモ – 仕様変更時に詰まったら、まず実ヘッダ・ダッシュボード設定・上流TTLを同じ表にまとめ、どの層でキャッシュされているかを切り分けます
よくある事故と復旧Runbook(SSE詰まり・古いキャッシュ・_rsc不整合)
僕が現場でよく見る事故は3つです。1つ目はSSEがrewrite経由でバッファされる問題です。2つ目はrevalidateTag/revalidatePathを叩いたのにCDNが古いまま残る問題です。3つ目は_rscを含むリクエストでVaryが足りず、ユーザーごとに表示がズレる問題です。Next.jsのCDNガイドでも、Data Cache更新だけではCDNは即時更新されない点が明記されています。
復旧手順の型
- SSE詰まり – rewriteを外してRoute Handlerの自前プロキシに切り替えます
- 古いキャッシュ残留 – 上流でタグを返し、タグ単位でinvalidateします
- _rsc不整合 –
_rscをキャッシュキーに含め、Varyを不足なく返します
# 例: タグ無効化
vercel cache invalidate --tag post:123
// 例: Varyの明示
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Accept-Encoding
復旧を速くしたいなら、手順を文章ではなくコマンドで残すのがおすすめです。夜間対応で判断がブレにくくなります。
本番運用チェックリスト: タグ無効化・段階ロールアウト・コスト監視
実装が終わったあとに差が出るのは運用です。ここは「デプロイできたか」ではなく「期待どおりに更新されるか」で判断します。特にrewrite周りは、機能テストが通ってもキャッシュ戦略がずれていると、後からコストと鮮度が同時に悪化しやすいです。本番は段階ロールアウト前提で進めるのが安全です。
- 新規/既存の挙動差を記録 – 2026-04-06境界の前提を運用ドキュメント化します
- TTLの責務分離を固定 – 3層ヘッダをテンプレート化して再利用します
- _rscとVaryを検証 – App Router経由のレスポンスを専用にチェックします
- タグ運用を導入 – 対象ページ単位でinvalidateできる粒度にします
- 段階リリース – まず一部パスのみ新TTLへ切り替えます
- 指標監視 – HIT率、TTFB、origin転送量、エラー率を同時に見ます
- サイズ監視 – 10MB/20MB上限を超えるレスポンスを検知します
- 週次レビュー – 「速いが古い」「新しいが遅い」の偏りを修正します
- 補足 – 設計レビューでは、対象パス・上流ヘッダ・除外条件・タグ無効化手順を1枚にまとめてから確認すると、見落としが減ります
この変更を知らないまま1年運用すると起こること
この仕様差を知らないままだと、まず「更新したのに反映されない」問い合わせが増えます。次に、originへの無駄なアクセスが増えてコストが読めなくなります。最後に、_rscやVaryの不整合でユーザーごとに違う画面が見える可能性があります。どれも一気に壊れるというより、じわじわ信用を削るタイプです。気づいた時には原因が分散していて直しづらいので、今のうちに設計をそろえておくのが安心です。
この記事を書いている理由
僕自身、2025年に運用したWeb招待状サービスで90日以上のログイン継続率を追いながら、表示速度と更新反映のバランスにかなり苦労しました。2026年4月2日にはVercelの既定変更チェックリストも書いたんですが、実際に案件へ入ると「知識だけ」では守り切れない場面が多かったです。だから今回は、Next.js 16.2前提で壊さない実装手順まで落としてまとめました。僕がハマったところを先回りで共有できれば、同じ遠回りを減らせると思ったからです。
次のアクション
まずは本番URLに対してcurl -Iを3本だけ実行して、現状のヘッダとVaryを確認してみてください。ここが見えるだけで、次の修正優先度が一気に明確になります。
今日からできるアクション
- 30分で現状把握 – rewrite対象パスの実ヘッダを採取して一覧化する
- 1時間でテンプレ適用 – 3層Cache-Controlとfallback順序を固定する
- 検証ログを残す – 実測ヘッダ、HIT率、origin転送量、除外パスを週次で見直す