リライト (rewrites)

リライト (rewrites) を使用すると、受信リクエストパスを別の宛先パスにマッピングできます。

リライトはURLプロキシとして機能し、宛先パスをマスクするため、ユーザーがサイト上の位置を変更していないように見えます。一方、リダイレクト (redirects) は新しいページに再ルーティングされ、URLの変更が表示されます。

リライトを使用するには、next.config.jsrewritesキーを使用します:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/about',
        destination: '/',
      },
    ]
  },
}

リライトはクライアントサイドルーティングに適用され、上記の例では<Link href="/about">にリライトが適用されます。

rewritesは非同期関数で、sourcedestinationプロパティを持つオブジェクトの配列、または配列のオブジェクト(下記参照)を返すことが期待されます:

  • source: String - 受信リクエストのパターン
  • destination: String - ルーティングしたいパス
  • basePath: false または undefined - falseの場合、マッチング時にbasePathが含まれません。外部リライトのみに使用可能
  • locale: false または undefined - マッチング時にロケールを含めないかどうか
  • has - typekeyvalueプロパティを持つhasオブジェクトの配列
  • missing - typekeyvalueプロパティを持つmissingオブジェクトの配列

rewrites関数が配列を返す場合、リライトはファイルシステム(ページと/publicファイル)のチェック後、動的ルートの前に適用されます。rewrites関数が特定の形状の配列オブジェクトを返す場合、Next.jsのv10.1以降、この動作を変更し、より細かく制御できます:

next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        // これらのリライトはヘッダー/リダイレクトのチェック後、
        // _next/publicファイルを含むすべてのファイルの前にチェックされ、
        // ページファイルの上書きを許可します
        {
          source: '/some-page',
          destination: '/somewhere-else',
          has: [{ type: 'query', key: 'overrideMe' }],
        },
      ],
      afterFiles: [
        // これらのリライトはページ/publicファイルのチェック後、
        // 動的ルートの前にチェックされます
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // これらのリライトはページ/publicファイルと
        // 動的ルートのチェック後にチェックされます
        {
          source: '/:path*',
          destination: `https://my-old-site.com/:path*`,
        },
      ],
    }
  },
}

知っておくと良い: beforeFilesのリライトは、ソースにマッチした後すぐにファイルシステム/動的ルートをチェックせず、すべてのbeforeFilesがチェックされるまで続きます。

Next.jsのルートチェック順序は以下の通りです:

  1. headers がチェック/適用される
  2. redirects がチェック/適用される
  3. beforeFilesリライトがチェック/適用される
  4. publicディレクトリの静的ファイル、_next/staticファイル、非動的ページがチェック/提供される
  5. afterFilesリライトがチェック/適用され、これらのリライトのいずれかがマッチすると、各マッチ後に動的ルート/静的ファイルをチェック
  6. fallbackリライトがチェック/適用され、これらは404ページのレンダリング前、動的ルート/すべての静的アセットのチェック後に適用されます。getStaticPathsfallback: true/'blocking'を使用する場合、next.config.jsで定義されたfallback rewritesは実行_されません_。

リライトパラメータ

リライトでパラメータを使用する場合、destinationでパラメータが使用されていない場合、パラメータはデフォルトでクエリに渡されます。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // :pathパラメータはここで使用されていないため、自動的にクエリに渡されます
      },
    ]
  },
}

パラメータがdestinationで使用されている場合、パラメータは自動的にクエリに渡されません。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // :pathパラメータはここで使用されているため、自動的にクエリに渡されません
      },
    ]
  },
}

destinationですでにパラメータが使用されている場合でも、destinationでクエリを指定することで、手動でパラメータをクエリに渡すことができます。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // :firstパラメータがdestinationで使用されているため、:secondパラメータは
        // 自動的にクエリに追加されませんが、上記のように手動で追加できます
      },
    ]
  },
}

知っておくと良い: Automatic Static Optimization からの静的ページや prerendering からのパラメータは、ハイドレーション後にクライアント側で解析され、クエリで提供されます。

パスマッチング

パスマッチングが許可されています。例えば/blog/:slug/blog/hello-worldにマッチします(ネストされたパスは不可):

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // マッチしたパラメータをdestinationで使用可能
      },
    ]
  },
}

ワイルドカードパスマッチング

ワイルドカードパスにマッチさせるには、パラメータの後に*を使用します。例えば/blog/:slug*/blog/a/b/c/d/hello-worldにマッチします:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // マッチしたパラメータをdestinationで使用可能
      },
    ]
  },
}

正規表現パスマッチング

正規表現パスにマッチさせるには、パラメータの後に正規表現を括弧で囲みます。例えば/blog/:slug(\\d{1,})/blog/123にマッチしますが、/blog/abcにはマッチしません:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-blog/:post(\\d{1,})',
        destination: '/blog/:post', // マッチしたパラメータをdestinationで使用可能
      },
    ]
  },
}

以下の文字(, ), {, }, [, ], |, \, ^, ., :, *, +, -, ?, $は正規表現パスマッチングに使用されるため、sourceで特殊値として使用されない場合は、\\を前に付けてエスケープする必要があります:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // これは`/english(default)/something`がリクエストされた場合にマッチします
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

ヘッダー、クッキー、クエリのマッチング

リライトをヘッダー、クッキー、またはクエリ値もマッチする場合にのみ適用するには、hasフィールドを使用します。またはマッチしない場合に適用するにはmissingフィールドを使用します。リライトが適用されるには、sourceとすべてのhasアイテムがマッチし、すべてのmissingアイテムがマッチしない必要があります。

hasmissingアイテムは以下のフィールドを持つことができます:

  • type: String - headercookiehost、またはqueryのいずれかでなければなりません
  • key: String - マッチ対象の選択されたタイプのキー
  • value: String または undefined - チェックする値。undefinedの場合、任意の値がマッチします。正規表現のような文字列を使用して値の特定の部分をキャプチャできます。例えば、first-(?<paramName>.*)という値をfirst-secondに使用すると、second:paramNameとしてdestinationで使用可能になります
next.config.js
module.exports = {
  async rewrites() {
    return [
      // ヘッダー`x-rewrite-me`が存在する場合、
      // このリライトが適用されます
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // ヘッダー`x-rewrite-me`が存在しない場合、
      // このリライトが適用されます
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // ソース、クエリ、クッキーがマッチした場合、
      // このリライトが適用されます
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // ページ値はdestinationで利用できません
            // 値が提供され、名前付きキャプチャグループ(例: (?<page>home))が
            // 使用されていないためです
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // ヘッダー`x-authorized`が存在し、
      // マッチする値が含まれている場合、このリライトが適用されます
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // ホストが`example.com`の場合、
      // このリライトが適用されます
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        destination: '/another-page',
      },
    ]
  },
}

外部URLへのリライト

リライトを使用して外部URLにリライトできます。これはNext.jsを段階的に採用する場合に特に便利です。以下は、メインアプリの/blogルートを外部サイトにリダイレクトするリライトの例です。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog',
        destination: 'https://example.com/blog',
      },
      {
        source: '/blog/:slug',
        destination: 'https://example.com/blog/:slug', // マッチしたパラメータをdestinationで使用可能
      },
    ]
  },
}

trailingSlash: trueを使用している場合、sourceパラメータに末尾のスラッシュを挿入する必要もあります。宛先サーバーも末尾のスラッシュを期待している場合は、destinationパラメータにも含める必要があります。

next.config.js
module.exports = {
  trailingSlash: true,
  async rewrites() {
    return [
      {
        source: '/blog/',
        destination: 'https://example.com/blog/',
      },
      {
        source: '/blog/:path*/',
        destination: 'https://example.com/blog/:path*/',
      },
    ]
  },
}

Next.jsの段階的採用

Next.jsルートをすべてチェックした後、既存のウェブサイトへのプロキシにフォールバックさせることもできます。

この方法では、より多くのページをNext.jsに移行する際にリライト設定を変更する必要がありません

next.config.js
module.exports = {
  async rewrites() {
    return {
      fallback: [
        {
          source: '/:path*',
          destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
        },
      ],
    }
  },
}

basePathサポート付きリライト

basePathサポートをリライトと共に使用する場合、各sourcedestinationには、リライトにbasePath: falseを追加しない限り、自動的にbasePathがプレフィックスとして追加されます:

next.config.js
module.exports = {
  basePath: '/docs',

  async rewrites() {
    return [
      {
        source: '/with-basePath', // 自動的に /docs/with-basePath になる
        destination: '/another', // 自動的に /docs/another になる
      },
      {
        // basePath: falseが設定されているため /without-basePath に /docs を追加しない
        // 注意: これは`destination: '/another'`のような内部リライトには使用できません
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

バージョン履歴

バージョン変更点
v13.3.0missing 追加
v10.2.0has 追加
v9.5.0ヘッダーサポート追加