rewrites

Rewrites를 사용하면 들어오는 요청 경로를 다른 목적지 경로로 매핑할 수 있습니다.

Rewrites는 URL 프록시 역할을 하며, 목적지 경로를 마스킹하여 사용자가 사이트의 위치가 변경되지 않은 것처럼 보이게 합니다. 반면 redirects는 새 페이지로 라우팅하여 URL 변경 사항을 보여줍니다.

Rewrites를 사용하려면 next.config.js에서 rewrites 키를 사용할 수 있습니다:

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

Rewrites는 클라이언트 측 라우팅에 적용되며, 위 예제에서 <Link href="/about">는 rewrite가 적용됩니다.

rewritessourcedestination 속성을 가진 객체를 포함하는 배열 또는 배열 객체를 반환해야 하는 비동기 함수입니다:

  • source: String - 들어오는 요청 경로 패턴입니다.
  • destination: String - 라우팅하려는 경로입니다.
  • basePath: false 또는 undefined - false인 경우 매칭 시 basePath가 포함되지 않으며, 외부 rewrites에만 사용할 수 있습니다.
  • locale: false 또는 undefined - 매칭 시 로케일이 포함되지 않아야 하는지 여부입니다.
  • hastype, keyvalue 속성을 가진 has 객체의 배열입니다.
  • missingtype, keyvalue 속성을 가진 missing 객체의 배열입니다.

rewrites 함수가 배열을 반환할 때, rewrites는 파일 시스템(페이지 및 /public 파일)을 확인한 후 동적 경로 전에 적용됩니다. rewrites 함수가 특정 형식의 배열 객체를 반환할 때, 이 동작을 변경하고 더 세밀하게 제어할 수 있습니다. 이는 Next.js v10.1부터 가능합니다:

next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        // 이 rewrites는 헤더/리디렉션 후에 확인되며
        // _next/public 파일을 포함한 모든 파일 전에 확인되어
        // 페이지 파일을 덮어쓸 수 있습니다
        {
          source: '/some-page',
          destination: '/somewhere-else',
          has: [{ type: 'query', key: 'overrideMe' }],
        },
      ],
      afterFiles: [
        // 이 rewrites는 페이지/공용 파일을 확인한 후에 확인되며
        // 동적 경로 전에 확인됩니다
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // 이 rewrites는 페이지/공용 파일과
        // 동적 경로를 확인한 후에 확인됩니다
        {
          source: '/:path*',
          destination: `https://my-old-site.com/:path*`,
        },
      ],
    }
  },
}

참고: beforeFiles에 있는 rewrites는 소스와 일치한 후 파일 시스템/동적 경로를 즉시 확인하지 않고, 모든 beforeFiles가 확인될 때까지 계속됩니다.

Next.js 라우트가 확인되는 순서는 다음과 같습니다:

  1. headers가 확인/적용됩니다.
  2. redirects가 확인/적용됩니다.
  3. beforeFiles rewrites가 확인/적용됩니다.
  4. public 디렉토리의 정적 파일, _next/static 파일, 및 비동적 페이지가 확인/제공됩니다.
  5. afterFiles rewrites가 확인/적용됩니다. 이러한 rewrites 중 하나가 일치하면 각 일치 후 동적 경로/정적 파일을 확인합니다.
  6. fallback rewrites가 확인/적용됩니다. 이는 404 페이지를 렌더링하기 전에 적용되며, 동적 경로/모든 정적 자산을 확인한 후에 적용됩니다. getStaticPaths에서 fallback: true/'blocking'를 사용하는 경우, next.config.js에 정의된 fallback rewrites는 실행되지 않습니다.

Rewrite parameters

Rewrite에서 매개변수를 사용할 때, 매개변수가 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에서 이미 하나의 매개변수가 사용되는 경우, 쿼리에 매개변수를 수동으로 전달할 수 있습니다.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // :first 매개변수가 destination에서 사용되므로 :second 매개변수가
        // 쿼리에 자동으로 추가되지 않습니다. 그러나 위와 같이 수동으로 추가할 수 있습니다
      },
    ]
  },
}

참고: 자동 정적 최적화 또는 사전 렌더링에서 rewrites의 매개변수는 클라이언트가 하이드레이션 후 쿼리에서 파싱됩니다.

Path Matching

경로 매칭이 허용됩니다. 예를 들어 /blog/:slug/blog/hello-world와 일치합니다(중첩 경로 없음):

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // 매칭된 매개변수는 목적지에서 사용할 수 있습니다
      },
    ]
  },
}

Wildcard Path Matching

와일드카드 경로를 매칭하려면 매개변수 뒤에 *를 사용할 수 있습니다. 예를 들어 /blog/:slug*/blog/a/b/c/d/hello-world와 일치합니다:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug
 
*', // 매칭된 매개변수는 목적지에서 사용할 수 있습니다
      },
    ]
  },
}

Regex Path Matching

정규식 경로를 매칭하려면 매개변수 뒤에 괄호로 정규식을 감쌀 수 있습니다. 예를 들어 /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', // 매칭된 매개변수는 목적지에서 사용할 수 있습니다
      },
    ]
  },
}

다음 문자는 정규식 경로 매칭에 사용되므로, source에서 비특수 값으로 사용될 때는 앞에 \\를 추가하여 이스케이프해야 합니다: (, ), {, }, [, ], |, \, ^, ., :, *, +, -, ?, $

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // `/english(default)/something`이 요청될 때 일치합니다
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

Header, Cookie, and Query Matching

헤더, 쿠키 또는 쿼리 값이 has 필드와 일치하거나 missing 필드와 일치하지 않을 때만 rewrite를 매칭하려면, has 필드 또는 missing 필드를 사용할 수 있습니다. source와 모든 has 항목이 일치하고 모든 missing 항목이 일치하지 않아야 rewrite가 적용됩니다.

hasmissing 항목에는 다음 필드가 있을 수 있습니다:

  • type: String - header, cookie, host 또는 query 중 하나여야 합니다.
  • key: String - 일치시킬 선택된 유형의 키입니다.
  • value: String 또는 undefined - 확인할 값입니다. undefined인 경우, 모든 값이 일치합니다. 정규식과 같은 문자열을 사용하여 값의 특정 부분을 캡처할 수 있습니다. 예: 값이 first-(?<paramName>.*)인 경우, first-secondsecond가 되어 목적지에서 :paramName으로 사용할 수 있습니다.
next.config.js
module.exports = {
  async rewrites() {
    return [
      // 헤더 `x-rewrite-me`가 있는 경우,
      // 이 rewrite가 적용됩니다
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // 헤더 `x-rewrite-me`가 없는 경우,
      // 이 rewrite가 적용됩니다
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // 소스, 쿼리 및 쿠키가 일치하는 경우,
      // 이 rewrite가 적용됩니다
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // 페이지 값은 제공된 값이 있고
            // 명명된 캡처 그룹을 사용하지 않으므로
            // 목적지에서 사용할 수 없습니다. 예: (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // 헤더 `x-authorized`가 존재하고
      // 일치하는 값을 포함하는 경우, 이 rewrite가 적용됩니다
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // 호스트가 `example.com`인 경우,
      // 이 rewrite가 적용됩니다
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        destination: '/another-page',
      },
    ]
  },
}

Rewriting to an external URL

Examples

Rewrites를 사용하면 외부 URL로 rewrite할 수 있습니다. 이는 점진적으로 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', // 매칭된 매개변수는 목적지에서 사용할 수 있습니다
      },
    ]
  },
}

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*/',
      },
    ]
  },
}

Incremental adoption of Next.js

Next.js가 모든 Next.js 경로를 확인한 후 기존 웹사이트로 프록시하도록 할 수도 있습니다.

이렇게 하면 더 많은 페이지를 Next.js로 마이그레이션할 때 rewrites 구성을 변경할 필요가 없습니다.

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

Rewrites with basePath support

리디렉션과 함께 basePath 지원을 활용할 때, 각 sourcedestinationnext.config.jsbasePath: false를 추가하지 않는 한 자동으로 basePath로 접두사가 추가됩니다:

next.config.js
module.exports = {
  basePath: '/docs',
 
  async rewrites() {
    return [
      {
        source: '/with-basePath', // 자동으로 /docs/with-basePath가 됩니다
        destination: '/another', // 자동으로 /docs/another가 됩니다
      },
      {
        // basePath: false가 설정되어 있으므로 /docs가 추가되지 않습니다
        // 참고: 이는 내부 rewrites에 사용할 수 없습니다. 예: `destination: '/another'`
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

Rewrites with i18n support

리디렉션과 함께 i18n 지원을 활용할 때, 각 sourcedestination은 구성된 locales를 처리하도록 자동으로 접두사가 추가되며, 리디렉션에 locale: false를 추가하지 않는 한 자동으로 처리됩니다. locale: false를 사용하는 경우, sourcedestination에 로케일을 접두사로 추가해야 올바르게 매칭됩니다.

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },
 
  async rewrites() {
    return [
      {
        source: '/with-locale', // 모든 로케일을 자동으로 처리합니다
        destination: '/another', // 로케
 
일을 자동으로 전달합니다
      },
      {
        // locale: false가 설정되어 있으므로 로케일을 자동으로 처리하지 않습니다
        source: '/nl/with-locale-manual',
        destination: '/nl/another',
        locale: false,
      },
      {
        // `en`이 defaultLocale이므로 '/'와 일치합니다
        source: '/en',
        destination: '/en/another',
        locale: false,
      },
      {
        // locale: false가 설정된 경우에도 모든 로케일을 매칭할 수 있습니다
        source: '/:locale/api-alias/:path*',
        destination: '/api/:path*',
        locale: false,
      },
      {
        // 이것은 /(en|fr|de)/(.*)로 변환되므로 최상위 수준의
        // `/` 또는 `/fr` 경로와 일치하지 않습니다
        source: '/(.*)',
        destination: '/another',
      },
    ]
  },
}

Version History

VersionChanges
v13.3.0missing 추가됨.
v10.2.0has 추가됨.
v9.5.0Headers 추가됨.