Next.jsのpublicディレクトリ内のファイルのキャッシュの挙動
Next.jsのpublicディレクトリに配置した静的ファイルのキャッシュの挙動について、あまりまとまった情報が見つからなかったのでまとめておく。next@v12.1.0で調査を行っており、今後バージョンアップで挙動が変わる可能性があることに注意。
Vercelにデプロイしたとき
VercelにNext.jsをデプロイしたとき、publicディレクトリ内に配置された静的ファイルのキャッシュは以下のようになる。
- CDNには長期間キャッシュされる(
x-vercel-cache: HIT)。デプロイを行うとCDNのキャッシュはクリアされる - ブラウザにはファイルの内容はキャッシュされない(
max-age=0)- ただしブラウザが
etagの値を覚えておいてくれて、次回リクエスト時には304レスポンスとなりオリジンサーバーへの負荷は軽減されていたりする
- ただしブラウザが

「ブラウザにキャッシュしてリクエストが飛ばないようにしてほしい」と思う人もいるかもしれないが、ブラウザにキャッシュされると同一パスのファイルの内容が変わったときにキャッシュされた古い内容が表示され続けてしまう。
ブラウザにキャッシュしつつ、新しいデプロイではURLのクエリ文字列を変えるようにすれば常に最新のファイルが読み込まれるようにすることも可能だが、リリース時に考えなければいけないことが増える。そういう意味でこの挙動は理想的だと思う。
セルフホスティングしたとき
publicディレクトリのファイルのレスポンスヘッダにはデフォルトではCache-Control: public, max-age=0が付く模様。CDNがレスポンスヘッダの値に応じてキャッシュを行う設定になっている場合、CDNにもブラウザにもファイル自体はキャッシュされないことになる。
Cache-Controlの値を変えたければnext.config.jsでCustom Headersの設定をすれば良い。Vercelと同じ挙動を実現する方法は使用するCDNによって色々とやり方があるはず。
たとえばCache-Controlをs-maxage=86400, max-age=0とすれば、CDNには86400秒キャッシュしつつ(s-maxageを優先してくれる)、ブラウザにはキャッシュしない(max-ageを見てくれる)という挙動が実現できるかもしれない。もちろんファイルの内容が変わるときにはデプロイ後にCDNのキャッシュクリアが必要になる。