logo

アルパカログ

Next.js+Google Cloud CDNで静的ファイルをキャッシュする

Next.js アプリケーションを Vercel でホストする場合、私たち開発者が何も考えなくても Vercel が JS ファイルや画像ファイルなどの静的ファイルを良い感じにキャッシュしてくれます。

一方、Vercel 以外でホストする場合には、当然ながらキャッシュ周りを自分で設定する必要があります。

このエントリでは、Next.js を Google Cloud にホストしたケースを想定して静的ファイルをキャッシュする方法を紹介します。

Cloud CDNのキャッシュ条件

Cloud CDN では下記の条件を満たしているときコンテンツをキャッシュします。Next.js を普通に使っている限りは問題ないと思います。

また、Cloud CDN はキャッシュ制御ディレクティブに沿ってコンテンツをキャッシュします。

max-age ディレクティブがある場合はその指定秒間 CDN にキャッシュします。

s-maxage ディレクティブがある場合は max-age ディレクティブよりも優先されます。

また、 stale-while-revalidate も利用可能です。

_next/static 以下の静的ファイル

Next.js のビルドで生成される静的ファイルは _next/static ディレクトリ以下に配置されます。

これらのファイルをレスポンスする場合は Next.js がヘッダに自動的に cache-control: public,max-age=7200,immutable を付けてくれます。ついでに言うと etag も付きます。

ですので _next/static のファイルは特に考慮しなくても CDN にキャッシュされます。

public 以下の静的ファイル

public ディレクトリ以下の静的ファイルは、レスポンスヘッダに cache-control: public,max-age=0 のように max-age=0 が付くため実質的に CDN にはキャッシュされず、毎回オリジンサーバーにリクエストが行きます。

これを防ぐには、 next.config.jsheaders ディレクティブでレスポンスヘッダを明示的に指定する必要があります。

例えば、 public ディレクトリにある favicon.ico ファイルと images/ ディレクトリ以下の全てのファイルをキャッシュする場合は下記のようにします。

module.exports = {
  headers() {
    return [
      {
        source: '/favicon.ico',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=2592000, stale-while-revalidate=86400',
          },
        ],
      },
      {
        source: '/images/:path*',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=2592000, stale-while-revalidate=86400',
          },
        ],
      },
    ]
  },
}

参考

public ディレクトリ以下のファイルがデフォルトで max-age=0 を返してしまう件については、catnose さんも Next.jsのpublicディレクトリ内のファイルのキャッシュの挙動 で同様に書かれています。

以上です。このエントリでは Next.js を Google Cloud にホストしたケースを想定して静的ファイルをキャッシュする方法を紹介しました。