reescrituras (rewrites)

Las reescrituras le permiten mapear una ruta de solicitud entrante a una ruta de destino diferente.

Las reescrituras actúan como un proxy de URL y enmascaran la ruta de destino, haciendo parecer que el usuario no ha cambiado su ubicación en el sitio. En contraste, los redireccionamientos redirigirán a una nueva página y mostrarán los cambios en la URL.

Para usar reescrituras puede utilizar la clave rewrites en next.config.js:

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

Las reescrituras se aplican al enrutamiento del lado del cliente, un <Link href="/about"> tendrá la reescritura aplicada en el ejemplo anterior.

rewrites es una función asíncrona que espera devolver un arreglo o un objeto de arreglos (ver abajo) que contenga objetos con propiedades source y destination:

  • source: String - es el patrón de ruta de solicitud entrante.
  • destination: String es la ruta a la que desea dirigir.
  • basePath: false o undefined - si es false, el basePath no se incluirá al hacer coincidir, solo se puede usar para reescrituras externas.
  • locale: false o undefined - si no se debe incluir la configuración regional al hacer coincidir.
  • has es un arreglo de objetos has con las propiedades type, key y value.
  • missing es un arreglo de objetos missing con las propiedades type, key y value.

Cuando la función rewrites devuelve un arreglo, las reescrituras se aplican después de verificar el sistema de archivos (páginas y archivos /public) y antes de las rutas dinámicas. Cuando la función rewrites devuelve un objeto de arreglos con una forma específica, este comportamiento puede cambiarse y controlarse con mayor precisión, a partir de v10.1 de Next.js:

next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        // Estas reescrituras se verifican después de headers/redirects
        // y antes de todos los archivos, incluidos los archivos _next/public, lo que
        // permite anular archivos de página
        {
          source: '/some-page',
          destination: '/somewhere-else',
          has: [{ type: 'query', key: 'overrideMe' }],
        },
      ],
      afterFiles: [
        // Estas reescrituras se verifican después de los archivos pages/public
        // pero antes de las rutas dinámicas
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // Estas reescrituras se verifican después de los archivos pages/public
        // y las rutas dinámicas
        {
          source: '/:path*',
          destination: `https://my-old-site.com/:path*`,
        },
      ],
    }
  },
}

Bueno saber: las reescrituras en beforeFiles no verifican el sistema de archivos/rutas dinámicas inmediatamente después de coincidir con un source, continúan hasta que se hayan verificado todos los beforeFiles.

El orden en que Next.js verifica las rutas es:

  1. Se verifican/aplican los headers
  2. Se verifican/aplican los redirects
  3. Se verifican/aplican las reescrituras beforeFiles
  4. Se verifican/sirven los archivos estáticos del directorio public, archivos _next/static y páginas no dinámicas
  5. Se verifican/aplican las reescrituras afterFiles, si una de estas reescrituras coincide, verificamos las rutas dinámicas/archivos estáticos después de cada coincidencia
  6. Se verifican/aplican las reescrituras fallback, estas se aplican antes de renderizar la página 404 y después de verificar las rutas dinámicas/todos los recursos estáticos. Si usa fallback: true/'blocking' en getStaticPaths, las reescrituras fallback definidas en su next.config.js no se ejecutarán.

Parámetros de reescritura

Cuando se usan parámetros en una reescritura, los parámetros se pasarán en la consulta por defecto cuando ninguno de los parámetros se use en el destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // El parámetro :path no se usa aquí, por lo que se pasará automáticamente en la consulta
      },
    ]
  },
}

Si un parámetro se usa en el destino, ninguno de los parámetros se pasará automáticamente en la consulta.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // El parámetro :path se usa aquí, por lo que no se pasará automáticamente en la consulta
      },
    ]
  },
}

Aún puede pasar los parámetros manualmente en la consulta si uno ya se usa en el destino especificando la consulta en el destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // Dado que el parámetro :first se usa en el destino, el parámetro :second
        // no se agregará automáticamente en la consulta, aunque podemos agregarlo manualmente
        // como se muestra arriba
      },
    ]
  },
}

Bueno saber: Las páginas estáticas de Optimización Estática Automática o prerenderizado con parámetros de reescrituras se analizarán en el cliente después de la hidratación y se proporcionarán en la consulta.

Coincidencia de rutas

Se permiten coincidencias de rutas, por ejemplo /blog/:slug coincidirá con /blog/hello-world (sin rutas anidadas):

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // Los parámetros coincidentes se pueden usar en el destino
      },
    ]
  },
}

Coincidencia de rutas con comodín

Para coincidir con una ruta comodín puede usar * después de un parámetro, por ejemplo /blog/:slug* coincidirá con /blog/a/b/c/d/hello-world:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // Los parámetros coincidentes se pueden usar en el destino
      },
    ]
  },
}

Coincidencia de rutas con regex

Para coincidir con una ruta regex puede envolver la regex entre paréntesis después de un parámetro, por ejemplo /blog/:slug(\\d{1,}) coincidirá con /blog/123 pero no con /blog/abc:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-blog/:post(\\d{1,})',
        destination: '/blog/:post', // Los parámetros coincidentes se pueden usar en el destino
      },
    ]
  },
}

Los siguientes caracteres (, ), {, }, [, ], |, \, ^, ., :, *, +, -, ?, $ se usan para coincidencia de rutas regex, por lo que cuando se usan en el source como valores no especiales deben escaparse agregando \\ antes de ellos:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // esto coincidirá con `/english(default)/something` solicitado
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

Coincidencia de cabeceras, cookies y consultas

Para que una reescritura coincida solo cuando los valores de cabecera, cookie o consulta también coincidan, se puede usar el campo has o no coincidan con el campo missing. Tanto el source como todos los elementos has deben coincidir y todos los elementos missing no deben coincidir para que se aplique la reescritura.

Los elementos has y missing pueden tener los siguientes campos:

  • type: String - debe ser header, cookie, host o query.
  • key: String - la clave del tipo seleccionado para coincidir.
  • value: String o undefined - el valor a verificar, si es undefined cualquier valor coincidirá. Se puede usar una cadena tipo regex para capturar una parte específica del valor, por ejemplo, si el valor first-(?<paramName>.*) se usa para first-second, entonces second se podrá usar en el destino con :paramName.
next.config.js
module.exports = {
  async rewrites() {
    return [
      // si la cabecera `x-rewrite-me` está presente,
      // se aplicará esta reescritura
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // si la cabecera `x-rewrite-me` no está presente,
      // se aplicará esta reescritura
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // si coinciden el source, la consulta y la cookie,
      // se aplicará esta reescritura
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // el valor page no estará disponible en el
            // destino ya que se proporciona value y no
            // usa un grupo de captura nombrado, ej. (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // si la cabecera `x-authorized` está presente y
      // contiene un valor coincidente, se aplicará esta reescritura
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // si el host es `example.com`,
      // se aplicará esta reescritura
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        destination: '/another-page',
      },
    ]
  },
}

Reescritura a una URL externa

Ejemplos

Las reescrituras le permiten reescribir a una URL externa. Esto es especialmente útil para adoptar Next.js incrementalmente. El siguiente es un ejemplo de reescritura para redirigir la ruta /blog de su aplicación principal a un sitio externo.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog',
        destination: 'https://example.com/blog',
      },
      {
        source: '/blog/:slug',
        destination: 'https://example.com/blog/:slug', // Los parámetros coincidentes se pueden usar en el destino
      },
    ]
  },
}

Si está usando trailingSlash: true, también necesita insertar una barra diagonal al final en el parámetro source. Si el servidor de destino también espera una barra diagonal final, debe incluirse también en el parámetro 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*/',
      },
    ]
  },
}

Adopción incremental de Next.js

También puede hacer que Next.js recurra a proxy a un sitio web existente después de verificar todas las rutas de Next.js.

De esta manera no tiene que cambiar la configuración de reescrituras cuando migre más páginas a Next.js

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

Reescrituras con soporte basePath

Cuando se aprovecha el soporte de basePath con reescrituras, cada source y destination se prefija automáticamente con el basePath a menos que agregue basePath: false a la reescritura:

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

  async rewrites() {
    return [
      {
        source: '/with-basePath', // automáticamente se convierte en /docs/with-basePath
        destination: '/another', // automáticamente se convierte en /docs/another
      },
      {
        // no agrega /docs a /without-basePath ya que basePath: false está configurado
        // Nota: esto no se puede usar para reescrituras internas, ej. `destination: '/another'`
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

Historial de versiones

VersiónCambios
v13.3.0Se agregó missing.
v10.2.0Se agregó has.
v9.5.0Se agregaron cabeceras.

On this page