Cómo migrar de Pages al App Router
Esta guía le ayudará a:
- Actualizar su aplicación Next.js de la versión 12 a la versión 13
- Mejorar características que funcionan tanto en el directorio
pages
como enapp
- Migrar incrementalmente su aplicación existente de
pages
aapp
Actualización
Versión de Node.js
La versión mínima de Node.js es ahora v18.17. Consulte la documentación de Node.js para más información.
Versión de Next.js
Para actualizar a Next.js versión 13, ejecute el siguiente comando usando su gestor de paquetes preferido:
Versión de ESLint
Si está usando ESLint, necesita actualizar su versión de ESLint:
Nota importante: Puede que necesite reiniciar el servidor de ESLint en VS Code para que los cambios surtan efecto. Abra la Paleta de Comandos (
cmd+shift+p
en Mac;ctrl+shift+p
en Windows) y busqueESLint: Restart ESLint Server
.
Próximos pasos
Después de actualizar, consulte las siguientes secciones para los próximos pasos:
- Mejorar nuevas características: Una guía para ayudarle a actualizar a nuevas características como los componentes mejorados de Image y Link.
- Migrar del directorio
pages
aapp
: Una guía paso a paso para migrar incrementalmente del directoriopages
aapp
.
Mejorando nuevas características
Next.js 13 introdujo el nuevo App Router con nuevas características y convenciones. El nuevo Router está disponible en el directorio app
y coexiste con el directorio pages
.
Actualizar a Next.js 13 no requiere usar el App Router. Puede continuar usando pages
con nuevas características que funcionan en ambos directorios, como el componente Image actualizado, el componente Link, el componente Script y la optimización de fuentes.
Componente <Image/>
Next.js 12 introdujo mejoras al Componente Image con una importación temporal: next/future/image
. Estas mejoras incluían menos JavaScript del lado del cliente, formas más fáciles de extender y estilizar imágenes, mejor accesibilidad y carga diferida nativa del navegador.
En la versión 13, este nuevo comportamiento es ahora el predeterminado para next/image
.
Hay dos codemods para ayudarle a migrar al nuevo Componente Image:
- Codemod
next-image-to-legacy-image
: Renombra de forma segura y automática las importaciones denext/image
anext/legacy/image
. Los componentes existentes mantendrán el mismo comportamiento. - Codemod
next-image-experimental
: Añade peligrosamente estilos en línea y elimina props no utilizados. Esto cambiará el comportamiento de los componentes existentes para que coincidan con los nuevos valores predeterminados. Para usar este codemod, primero debe ejecutar el codemodnext-image-to-legacy-image
.
Componente <Link>
El Componente <Link>
ya no requiere añadir manualmente una etiqueta <a>
como hijo. Este comportamiento se añadió como una opción experimental en la versión 12.2 y ahora es el predeterminado. En Next.js 13, <Link>
siempre renderiza <a>
y permite pasar props a la etiqueta subyacente.
Por ejemplo:
Para actualizar sus enlaces a Next.js 13, puede usar el codemod new-link
.
Componente <Script>
El comportamiento de next/script
se ha actualizado para soportar tanto pages
como app
, pero se necesitan algunos cambios para garantizar una migración fluida:
- Mueva cualquier script
beforeInteractive
que haya incluido previamente en_document.js
al archivo de diseño raíz (app/layout.tsx
). - La estrategia experimental
worker
aún no funciona enapp
y los scripts con esta estrategia deberán eliminarse o modificarse para usar una estrategia diferente (por ejemplo,lazyOnload
). - Los manejadores
onLoad
,onReady
yonError
no funcionarán en Componentes del Servidor, así que asegúrese de moverlos a un Componente del Cliente o eliminarlos por completo.
Optimización de fuentes
Anteriormente, Next.js le ayudaba a optimizar fuentes mediante CSS en línea. La versión 13 introduce el nuevo módulo next/font
que le permite personalizar su experiencia de carga de fuentes manteniendo un gran rendimiento y privacidad. next/font
es compatible tanto con los directorios pages
como app
.
Aunque CSS en línea sigue funcionando en pages
, no funciona en app
. Debe usar next/font
en su lugar.
Consulte la página Optimización de fuentes para aprender a usar next/font
.
Migrando de pages
a app
🎥 Ver: Aprenda a adoptar incrementalmente el App Router → YouTube (16 minutos).
Mudarse al App Router puede ser la primera vez que use características de React en las que Next.js se basa, como Componentes del Servidor, Suspense y más. Cuando se combinan con nuevas características de Next.js como archivos especiales y diseños, la migración implica nuevos conceptos, modelos mentales y cambios de comportamiento que aprender.
Recomendamos reducir la complejidad combinada de estas actualizaciones dividiendo su migración en pasos más pequeños. El directorio app
está diseñado intencionalmente para funcionar simultáneamente con el directorio pages
para permitir una migración incremental página por página.
- El directorio
app
soporta rutas anidadas y diseños. Aprenda más. - Use carpetas anidadas para definir rutas y un archivo especial
page.js
para hacer un segmento de ruta accesible públicamente. Aprenda más. - Se usan convenciones de archivos especiales para crear la interfaz de usuario de cada segmento de ruta. Los archivos especiales más comunes son
page.js
ylayout.js
.- Use
page.js
para definir la interfaz de usuario única de una ruta. - Use
layout.js
para definir la interfaz de usuario compartida entre múltiples rutas. - Se pueden usar extensiones de archivo
.js
,.jsx
o.tsx
para archivos especiales.
- Use
- Puede colocar otros archivos dentro del directorio
app
como componentes, estilos, pruebas y más. Aprenda más. - Las funciones de obtención de datos como
getServerSideProps
ygetStaticProps
han sido reemplazadas con una nueva API dentro deapp
.getStaticPaths
ha sido reemplazado congenerateStaticParams
. pages/_app.js
ypages/_document.js
han sido reemplazados con un único diseño raízapp/layout.js
. Aprenda más.pages/_error.js
ha sido reemplazado con archivos especialeserror.js
más granulares. Aprenda más.pages/404.js
ha sido reemplazado con el archivonot-found.js
.- Las Rutas API
pages/api/*
han sido reemplazadas con el archivo especialroute.js
(Manejador de Ruta).
Paso 1: Creando el directorio app
Actualice a la última versión de Next.js (requiere 13.4 o superior):
Luego, cree un nuevo directorio app
en la raíz de su proyecto (o directorio src/
).
Paso 2: Creando un Diseño Raíz
Cree un nuevo archivo app/layout.tsx
dentro del directorio app
. Este es un diseño raíz que se aplicará a todas las rutas dentro de app
.
- El directorio
app
debe incluir un diseño raíz. - El diseño raíz debe definir las etiquetas
<html>
y<body>
ya que Next.js no las crea automáticamente. - El diseño raíz reemplaza los archivos
pages/_app.tsx
ypages/_document.tsx
. - Se pueden usar extensiones
.js
,.jsx
o.tsx
para archivos de diseño.
Para gestionar elementos HTML <head>
, puede usar el soporte SEO integrado:
Migrando _document.js
y _app.js
Si tiene un archivo _app
o _document
existente, puede copiar el contenido (por ejemplo, estilos globales) al diseño raíz (app/layout.tsx
). Los estilos en app/layout.tsx
no se aplicarán a pages/*
. Debe mantener _app
/_document
durante la migración para evitar que sus rutas pages/*
se rompan. Una vez migrado completamente, puede eliminarlos de forma segura.
Si está usando cualquier proveedor de contexto de React, deberá moverlos a un Componente del Cliente.
Migrando el patrón getLayout()
a Diseños (Opcional)
Next.js recomendaba añadir una propiedad a los componentes Page para lograr diseños por página en el directorio pages
. Este patrón puede reemplazarse con el soporte nativo para diseños anidados en el directorio app
.
Ver ejemplo antes y después
Antes
Después
-
Elimine la propiedad
Page.getLayout
depages/dashboard/index.js
y siga los pasos para migrar páginas al directorioapp
.app/dashboard/page.js -
Mueva el contenido de
DashboardLayout
a un nuevo Componente del Cliente para mantener el comportamiento del directoriopages
.app/dashboard/DashboardLayout.js -
Importe
DashboardLayout
en un nuevo archivolayout.js
dentro del directorioapp
.app/dashboard/layout.js -
Puede mover incrementalmente partes no interactivas de
DashboardLayout.js
(Componente del Cliente) alayout.js
(Componente del Servidor) para reducir la cantidad de JavaScript del componente que envía al cliente.
Paso 3: Migrando next/head
En el directorio pages
, el componente React next/head
se usa para gestionar elementos HTML <head>
como title
y meta
. En el directorio app
, next/head
se reemplaza con el nuevo soporte SEO integrado.
Antes:
Después:
Consulte todas las opciones de metadata.
Paso 4: Migrar páginas
- Las páginas en el directorio
app
son Componentes del Servidor (Server Components) por defecto. Esto es diferente del directoriopages
donde las páginas son Componentes del Cliente (Client Components). - La obtención de datos (data fetching) ha cambiado en
app
.getServerSideProps
,getStaticProps
ygetInitialProps
han sido reemplazados por una API más simple. - El directorio
app
utiliza carpetas anidadas para definir rutas y un archivo especialpage.js
para hacer accesible públicamente un segmento de ruta. -
Directorio pages
Directorio app
Ruta index.js
page.js
/
about.js
about/page.js
/about
blog/[slug].js
blog/[slug]/page.js
/blog/post-1
Recomendamos dividir la migración de una página en dos pasos principales:
- Paso 1: Mover el Componente de Página exportado por defecto a un nuevo Componente del Cliente.
- Paso 2: Importar el nuevo Componente del Cliente en un archivo
page.js
dentro del directorioapp
.
Bueno saber: Este es el camino de migración más fácil porque tiene el comportamiento más comparable al directorio
pages
.
Paso 1: Crear un nuevo Componente del Cliente
- Crea un nuevo archivo separado dentro del directorio
app
(ej.app/home-page.tsx
o similar) que exporte un Componente del Cliente. Para definir Componentes del Cliente, agrega la directiva'use client'
al inicio del archivo (antes de cualquier importación).- Similar al Enrutador de Páginas (Pages Router), hay un paso de optimización para pre-renderizar Componentes del Cliente a HTML estático en la carga inicial de la página.
- Mueve el componente de página exportado por defecto desde
pages/index.js
aapp/home-page.tsx
.
Paso 2: Crear una nueva página
-
Crea un nuevo archivo
app/page.tsx
dentro del directorioapp
. Este es un Componente del Servidor por defecto. -
Importa el Componente del Cliente
home-page.tsx
en la página. -
Si estabas obteniendo datos en
pages/index.js
, mueve la lógica de obtención de datos directamente al Componente del Servidor usando las nuevas APIs de obtención de datos. Consulta la guía de actualización de obtención de datos para más detalles. -
Si tu página anterior usaba
useRouter
, necesitarás actualizar a los nuevos hooks de enrutamiento. Aprende más. -
Inicia tu servidor de desarrollo y visita
http://localhost:3000
. Deberías ver tu ruta de índice existente, ahora servida a través del directorio app.
Paso 5: Migrar Hooks de Enrutamiento
Se ha agregado un nuevo enrutador para soportar el nuevo comportamiento en el directorio app
.
En app
, deberías usar los tres nuevos hooks importados desde next/navigation
: useRouter()
, usePathname()
, y useSearchParams()
.
- El nuevo hook
useRouter
se importa desdenext/navigation
y tiene un comportamiento diferente al hookuseRouter
enpages
que se importa desdenext/router
.- El hook
useRouter
importado desdenext/router
no es compatible en el directorioapp
pero puede seguir usándose en el directoriopages
.
- El hook
- El nuevo
useRouter
no devuelve el stringpathname
. Usa el hook separadousePathname
en su lugar. - El nuevo
useRouter
no devuelve el objetoquery
. Los parámetros de búsqueda (search params) y los parámetros de ruta dinámica ahora están separados. Usa los hooksuseSearchParams
yuseParams
en su lugar. - Puedes usar
useSearchParams
yusePathname
juntos para escuchar cambios de página. Consulta la sección Eventos del Enrutador (Router Events) para más detalles. - Estos nuevos hooks solo son compatibles en Componentes del Cliente. No pueden usarse en Componentes del Servidor.
Además, el nuevo hook useRouter
tiene los siguientes cambios:
isFallback
ha sido eliminado porquefallback
ha sido reemplazado.- Los valores
locale
,locales
,defaultLocales
,domainLocales
han sido eliminados porque las funciones integradas de i18n de Next.js ya no son necesarias en el directorioapp
. Aprende más sobre i18n. basePath
ha sido eliminado. La alternativa no será parte deuseRouter
. Aún no se ha implementado.asPath
ha sido eliminado porque el concepto deas
ha sido eliminado del nuevo enrutador.isReady
ha sido eliminado porque ya no es necesario. Durante el renderizado estático (static rendering), cualquier componente que use el hookuseSearchParams()
omitirá el paso de pre-renderizado y en su lugar se renderizará en el cliente en tiempo de ejecución.route
ha sido eliminado.usePathname
ouseSelectedLayoutSegments()
proporcionan una alternativa.
Consulta la referencia de la API de useRouter()
.
Compartir componentes entre pages
y app
Para mantener componentes compatibles entre los enrutadores pages
y app
, consulta el hook useRouter
desde next/compat/router
.
Este es el hook useRouter
del directorio pages
, pero destinado a usarse al compartir componentes entre enrutadores. Cuando estés listo para usarlo solo en el enrutador app
, actualiza al nuevo useRouter
desde next/navigation
.
Paso 6: Migrar Métodos de Obtención de Datos
El directorio pages
usa getServerSideProps
y getStaticProps
para obtener datos para las páginas. Dentro del directorio app
, estas funciones anteriores de obtención de datos son reemplazadas por una API más simple construida sobre fetch()
y Componentes del Servidor React asíncronos.
Renderizado del Lado del Servidor (getServerSideProps
)
En el directorio pages
, getServerSideProps
se usa para obtener datos en el servidor y pasar props al componente React exportado por defecto en el archivo. El HTML inicial para la página se pre-renderiza desde el servidor, seguido de "hidratar" la página en el navegador (haciéndola interactiva).
En el Enrutador de la Aplicación (App Router), podemos colocar nuestra obtención de datos dentro de nuestros componentes React usando Componentes del Servidor (Server Components). Esto nos permite enviar menos JavaScript al cliente, manteniendo el HTML renderizado desde el servidor.
Al establecer la opción cache
en no-store
, podemos indicar que los datos obtenidos nunca deben almacenarse en caché. Esto es similar a getServerSideProps
en el directorio pages
.
Acceder al Objeto de Solicitud
En el directorio pages
, puedes recuperar datos basados en solicitudes según la API HTTP de Node.js.
Por ejemplo, puedes recuperar el objeto req
desde getServerSideProps
y usarlo para obtener las cookies y cabeceras de la solicitud.
El directorio app
expone nuevas funciones de solo lectura para recuperar datos de solicitud:
headers
: Basado en la API Web Headers, y puede usarse dentro de Componentes del Servidor (Server Components) para recuperar cabeceras de solicitud.cookies
: Basado en la API Web Cookies, y puede usarse dentro de Componentes del Servidor (Server Components) para recuperar cookies.
Generación de Sitios Estáticos (getStaticProps
)
En el directorio pages
, la función getStaticProps
se usa para pre-renderizar una página en tiempo de compilación. Esta función puede usarse para obtener datos desde una API externa o directamente desde una base de datos, y pasar estos datos a toda la página mientras se genera durante la compilación.
En el directorio app
, la obtención de datos con fetch()
tendrá por defecto cache: 'force-cache'
, lo que almacenará en caché los datos de la solicitud hasta que se invaliden manualmente. Esto es similar a getStaticProps
en el directorio pages
.
Rutas dinámicas (getStaticPaths
)
En el directorio pages
, la función getStaticPaths
se utiliza para definir las rutas dinámicas que deben ser pre-renderizadas en el momento de construcción.
En el directorio app
, getStaticPaths
se reemplaza con generateStaticParams
.
generateStaticParams
se comporta de manera similar a getStaticPaths
, pero tiene una API simplificada para devolver parámetros de ruta y puede usarse dentro de layouts. La forma de retorno de generateStaticParams
es un array de segmentos en lugar de un array de objetos param
anidados o una cadena de rutas resueltas.
Usar el nombre generateStaticParams
es más apropiado que getStaticPaths
para el nuevo modelo en el directorio app
. El prefijo get
se reemplaza con un generate
más descriptivo, que encaja mejor ahora que getStaticProps
y getServerSideProps
ya no son necesarios. El sufijo Paths
se reemplaza por Params
, que es más apropiado para el enrutamiento anidado con múltiples segmentos dinámicos.
Reemplazando fallback
En el directorio pages
, la propiedad fallback
devuelta por getStaticPaths
se utiliza para definir el comportamiento de una página que no se ha pre-renderizado en el momento de construcción. Esta propiedad puede configurarse como true
para mostrar una página de respaldo mientras se genera la página, false
para mostrar una página 404, o blocking
para generar la página en el momento de la solicitud.
En el directorio app
, la propiedad config.dynamicParams
controla cómo se manejan los parámetros fuera de generateStaticParams
:
true
: (predeterminado) Los segmentos dinámicos no incluidos engenerateStaticParams
se generan bajo demanda.false
: Los segmentos dinámicos no incluidos engenerateStaticParams
devolverán un 404.
Esto reemplaza la opción fallback: true | false | 'blocking'
de getStaticPaths
en el directorio pages
. La opción fallback: 'blocking'
no está incluida en dynamicParams
porque la diferencia entre 'blocking'
y true
es insignificante con streaming.
Con dynamicParams
configurado como true
(el valor predeterminado), cuando se solicita un segmento de ruta que no ha sido generado, se renderizará en el servidor y se almacenará en caché.
Regeneración estática incremental (getStaticProps
con revalidate
)
En el directorio pages
, la función getStaticProps
permite agregar un campo revalidate
para regenerar automáticamente una página después de un cierto tiempo.
En el directorio app
, la obtención de datos con fetch()
puede usar revalidate
, que almacenará en caché la solicitud durante la cantidad de segundos especificada.
Rutas API
Las Rutas API continúan funcionando en el directorio pages/api
sin cambios. Sin embargo, han sido reemplazadas por Route Handlers en el directorio app
.
Los Route Handlers permiten crear manejadores de solicitudes personalizados para una ruta dada usando las APIs Web Request y Response.
Nota importante: Si anteriormente usaba rutas API para llamar a una API externa desde el cliente, ahora puede usar Server Components en su lugar para obtener datos de forma segura. Más información sobre obtención de datos.
Aplicaciones de una sola página (SPA)
Si también está migrando a Next.js desde una Aplicación de una sola página (SPA) al mismo tiempo, consulte nuestra documentación para obtener más información.
Paso 7: Estilos
En el directorio pages
, las hojas de estilo globales están restringidas solo a pages/_app.js
. Con el directorio app
, esta restricción se ha eliminado. Los estilos globales se pueden agregar a cualquier layout, página o componente.
Tailwind CSS
Si está usando Tailwind CSS, necesitará agregar el directorio app
a su archivo tailwind.config.js
:
También necesitará importar sus estilos globales en su archivo app/layout.js
:
Más información sobre estilos con Tailwind CSS
Usando App Router junto con Pages Router
Al navegar entre rutas servidas por los diferentes routers de Next.js, habrá una navegación dura. El prefetching automático de enlaces con next/link
no hará prefetch entre routers.
En su lugar, puede optimizar navegaciones entre App Router y Pages Router para conservar las transiciones de página prefetch y rápidas. Más información.
Codemods
Next.js proporciona transformaciones Codemod para ayudar a actualizar su base de código cuando una función está obsoleta. Consulte Codemods para más información.