コンテンツにスキップ

rewrites

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

リライトはURLプロキシとして機能し、宛先パスを隠すため、ユーザーがサイト上の場所を変更していないように見えます。対照的に、リダイレクトは新しいページに再ルーティングし、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は、typekey、およびvalueプロパティを持つhasオブジェクトの配列です。
  • missingは、typekey、およびvalueプロパティを持つmissingオブジェクトの配列です。

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

next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        // These rewrites are checked after headers/redirects
        // and before all files including _next/public files which
        // allows overriding page files
        {
          source: '/some-page',
          destination: '/somewhere-else',
          has: [{ type: 'query', key: 'overrideMe' }],
        },
      ],
      afterFiles: [
        // These rewrites are checked after pages/public files
        // are checked but before dynamic routes
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // These rewrites are checked after both pages/public files
        // and dynamic routes are checked
        {
          source: '/:path*',
          destination: `https://my-old-site.com/:path*`,
        },
      ],
    }
  },
}

補足: beforeFilesのリライトは、ソースにマッチした後すぐにファイルシステム/ダイナミックルートをチェックせず、すべてのbeforeFilesがチェックされるまで続行します。

Next.jsのルートがチェックされる順序は次のとおりです。

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

リライトパラメータ

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

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // The :path parameter isn't used here so will be automatically passed in the query
      },
    ]
  },
}

パラメータが宛先で使用されている場合、どのパラメータも自動的にクエリに渡されることはありません。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // The :path parameter is used here so will not be automatically passed in the query
      },
    ]
  },
}

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

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // Since the :first parameter is used in the destination the :second parameter
        // will not automatically be added in the query although we can manually add it
        // as shown above
      },
    ]
  },
}

補足: 自動静的最適化またはプリレンダリングによって生成された静的ページのリライトパラメータは、ハイドレーション後にクライアントでパースされ、クエリとして提供されます。

パスマッチング

パスの一致が許可されます。たとえば、/blog/:slug/blog/hello-worldと一致します(ネストされたパスは除く)。

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // Matched parameters can be used in the destination
      },
    ]
  },
}

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

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

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // Matched parameters can be used in the 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', // Matched parameters can be used in the destination
      },
    ]
  },
}

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

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // this will match `/english(default)/something` being requested
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

ヘッダー、Cookie、またはクエリの値がhasフィールドと一致するか、missingフィールドと一致しない場合にのみリライトを一致させるには、hasフィールドまたはmissingフィールドを使用できます。リライトが適用されるには、sourceとすべてのhas項目が一致し、すべてのmissing項目が一致しない必要があります。

hasmissing項目には、以下のフィールドを含めることができます。

  • type: String - headercookiehost、またはqueryのいずれかである必要があります。
  • key: String - 選択されたタイプから一致させるキー。
  • value: String または undefined - チェックする値。undefinedの場合、任意の値が一致します。値の特定の部分をキャプチャするために、正規表現のような文字列を使用できます。例えば、値first-(?<paramName>.*)first-secondに使用された場合、second:paramNameを使って宛先で使用可能になります。
next.config.js
module.exports = {
  async rewrites() {
    return [
      // if the header `x-rewrite-me` is present,
      // this rewrite will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // if the header `x-rewrite-me` is not present,
      // this rewrite will be applied
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // if the source, query, and cookie are matched,
      // this rewrite will be applied
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // the page value will not be available in the
            // destination since value is provided and doesn't
            // use a named capture group e.g. (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // if the header `x-authorized` is present and
      // contains a matching value, this rewrite will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // if the host is `example.com`,
      // this rewrite will be applied
      {
        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', // Matched parameters can be used in the 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サポートを利用する場合、basePath: falseをリライトに追加しない限り、各sourcedestinationには自動的にbasePathがプレフィックスとして付加されます。

next.config.js
module.exports = {
  basePath: '/docs',
 
  async rewrites() {
    return [
      {
        source: '/with-basePath', // automatically becomes /docs/with-basePath
        destination: '/another', // automatically becomes /docs/another
      },
      {
        // does not add /docs to /without-basePath since basePath: false is set
        // Note: this can not be used for internal rewrites e.g. `destination: '/another'`
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

i18nをサポートするリライト

リライトでi18nサポートを利用する場合、locale: falseをリライトに追加しない限り、各sourcedestinationには設定されたlocalesを処理するために自動的にプレフィックスが付加されます。locale: falseを使用する場合、正しく一致させるには、sourcedestinationにロケールをプレフィックスとして付加する必要があります。

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },
 
  async rewrites() {
    return [
      {
        source: '/with-locale', // automatically handles all locales
        destination: '/another', // automatically passes the locale on
      },
      {
        // does not handle locales automatically since locale: false is set
        source: '/nl/with-locale-manual',
        destination: '/nl/another',
        locale: false,
      },
      {
        // this matches '/' since `en` is the defaultLocale
        source: '/en',
        destination: '/en/another',
        locale: false,
      },
      {
        // it's possible to match all locales even when locale: false is set
        source: '/:locale/api-alias/:path*',
        destination: '/api/:path*',
        locale: false,
      },
      {
        // this gets converted to /(en|fr|de)/(.*) so will not match the top-level
        // `/` or `/fr` routes like /:path* would
        source: '/(.*)',
        destination: '/another',
      },
    ]
  },
}

バージョン履歴

バージョン変更点
v13.3.0missingが追加されました。
v10.2.0hasが追加されました。
v9.5.0ヘッダーが追加されました。