Guía práctica de migración de Next.js Pages Router a App Router: estrategia gradual y lista de errores comunes

El director técnico lanzó una pregunta en la reunión: «¿Podemos actualizar este proyecto de Next.js 12 a la 14?»
Miré la pantalla con ese proyecto antiguo que llevaba dos años en marcha. La última vez que subimos a React 17, tardamos una semana entera corrigiendo bugs y el soporte no paró de sonar.
Pero esta vez parecía distinto. Por la noche, en casa, repasé la documentación oficial y vi las novedades de App Router: Server Components, layouts anidados, mejor rendimiento… Me picó la curiosidad. Luego llegué a la guía de migración y me vino el desánimo: tablas de equivalencia de API por todas partes, qué hacer con getServerSideProps, cómo descomponer _app.js… Un lío.
Lo peor: la «migración gradual» que recomienda la documentación suena bien en teoría, pero en la práctica, al saltar entre /pages y /app, el usuario ve el spinner de carga y la experiencia empeora.
Pasé dos semanas enteras tropezando, leyendo debates en la comunidad y probando enfoques distintos. Al final armé una estrategia de migración que nos ha funcionado. En este artículo comparto esa experiencia:
- Cómo decidir si tu proyecto merece migrar
- Pros y contras reales de las dos estrategias (no la teoría del manual)
- Pasos detallados y ejemplos de código para migrar getServerSideProps
- Siete problemas gordos que viví en primera persona y cómo los resolví
Si dudas si actualizar o ya empezaste la migración y te atascaste, espero que esto te ahorre tiempo.
¿Por qué migrar? Haz primero los números
Antes de nada, un aviso: no todos los proyectos merecen el esfuerzo.
El mes pasado un amigo me preguntó si debían migrar a App Router una landing de campaña que iban a apagar en seis meses. Les dije que no: ¿para qué invertir tiempo en código que va a desaparecer?
Entonces, ¿cuándo sí compensa? Estos son los criterios que uso:
Necesidad de layouts anidados
Fue la razón principal de nuestro equipo. En el panel SaaS teníamos barra lateral + cabecera + zona de contenido en tres niveles. Con Pages Router, cada cambio de página re-renderizaba toda la barra lateral.
El usuario notaba un parpadeo al entrar en una página nueva. No era la red: era el re-dibujado del layout.
Los layouts anidados de App Router lo resolvieron. Tras la migración, el equipo de WorkOS reportó «una experiencia de inicio de sesión mucho mejor, sin estados de carga ni saltos de layout» — y en nuestras pruebas fue igual: al cambiar de página solo se actualiza el contenido; la navegación se queda fija.
Margen de optimización de rendimiento
Si tu primera carga supera los 3 segundos, App Router puede ayudar.
Teníamos una lista de productos con getServerSideProps: cada refresco esperaba a que el servidor generara todo el HTML. Con Server Components, los datos se obtienen en el servidor y se envían al cliente por streaming; el tiempo de primera carga bajó de 3,2 s a 1,8 s.
Ojo: no todas las páginas ganan velocidad. En páginas puramente interactivas (un editor de lienzo, por ejemplo), la diferencia es mínima o incluso puede ir un poco más lento por la capa extra de abstracción.
Proyectos con mantenimiento a largo plazo
Si el proyecto va a vivir más de tres años, migrar pronto paga. Vercel ya dejó claro que las novedades irán primero a App Router; Pages Router entra en «modo mantenimiento».
No quiero repetir la migración dentro de dos años, con APIs distintas y más trampas.
Escenarios en los que no conviene migrar
En estos casos, yo esperaría:
- Proyecto que va a cerrarse pronto — no merece la pena
- Sitio estático pequeño (menos de 5 páginas) — el beneficio es mínimo
- Equipo sin dominar React 18 — primero Suspense y Server Components
- Muchas librerías de terceros antiguas — probablemente encontrarás incompatibilidades
En resumen: no migres por migrar. Pregúntate qué problema real resuelves. Si la respuesta es «ninguno, solo quiero probar», mejor no.
Nosotros hicimos la cuenta: dos semanas de persona, a cambio de mejor UX y menos deuda técnica durante tres años. Nos salió rentable. ¿Y tu proyecto?
Elegir entre dos estrategias de migración
La documentación oficial recomienda la «migración gradual»: ir despacio, página a página.
Cuando la probé, encontré un problema serio.
La trampa de la migración gradual
Imagina: migras la home a /app, pero el detalle de producto sigue en /pages. El usuario entra desde la home al producto y ve pantalla en blanco, spinner… y luego el contenido.
¿Por qué? Al saltar de App Router a Pages Router, Next.js trata dos aplicaciones distintas y hay que recargar todo el bundle de JavaScript. La UX vuelve a 2010.
El equipo de WorkOS lo dijo en su blog: «navegar entre routers distintos es como saltar entre dos apps sin relación». Ellos también querían migración gradual y acabaron abandonándola.
¿Entonces la migración gradual no sirve? No del todo.
Cuándo sí encaja la migración gradual:
- Páginas poco acopladas (un blog donde los artículos no se enlazan entre sí)
- Migración por módulos completos (primero todo el área de usuario, luego productos)
- Se acepta un estado de carga al cambiar de router
Conozco un blog técnico que lo hizo así y le fue bien. En un SaaS o una tienda online, yo no lo intentaría.
El esquema sin downtime de WorkOS
¿Y los proyectos complejos? WorkOS propuso un truco elegante.
Crearon un directorio temporal /app/new, reescribieron ahí todas las páginas y usaron un parámetro de consulta para elegir la versión.
Suena enrevesado; el código lo aclara:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/:path*',
destination: '/new/:path*',
has: [
{
type: 'query',
key: 'new',
value: 'true',
},
],
},
]
},
}
Así, /dashboard sigue siendo la versión antigua; con ?new=true ves la nueva.
QA, producto y diseño pueden validar en producción sin que el usuario lo note. Cuando la nueva versión esté lista, mueves /app/new a /app, borras /pages y listo.
Nuestro equipo usó este esquema. Durante toda la migración no hubo un solo bug visible para el usuario: probamos una semana con datos reales antes del corte.
Pasos concretos:
- Actualizar Next.js a 14 — sin tocar /pages, solo el framework
- Migrar hooks de rutas — de
next/routeranext/navigation, compatible con ambos routers - Crear /app/new — reconstruir ahí la estructura de páginas
- Reutilizar componentes — importar los de /pages sin reescribir
- Configurar rewrites — el fragmento de arriba, con
?new=true - Pruebas internas + gris — el equipo usa la nueva versión y corrige
- Paso a producción — mover /app/new a /app, quitar rewrites y /pages
Del paso 1 al 7 tardamos 10 días laborables: 6 reescribiendo páginas, 3 corrigiendo bugs, 1 en el despliegue final.
Mi recomendación
Si tu proyecto:
- Tiene menos de 10 páginas y son independientes → migración gradual
- Tiene más de 10 páginas y la UX importa mucho → esquema sin downtime
- Es nuevo → App Router desde el inicio, sin vueltas
No intentes migrar mientras desarrollas funciones nuevas: lo probé y acabas con dos estilos de código que duelen a la vista. O dedicas dos semanas concentradas, o no toques nada aún.
Migración práctica de getServerSideProps
Es la pregunta que más me hacen: «getServerSideProps ya no existe, ¿cómo obtengo datos?»
En App Router es más simple; solo hay que cambiar el modelo mental.
De «separar» a «unificar»
En Pages Router, la obtención de datos (getServerSideProps) y la UI (componente) van separadas; Next.js ejecuta la función en el servidor y pasa el resultado al componente.
App Router no sigue ese patrón. El componente de página es una función async y obtiene los datos dentro:
// ❌ Forma antigua: pages/project/[id].tsx
export async function getServerSideProps(context) {
const { id } = context.params
const res = await fetch(`https://api.example.com/projects/${id}`)
const project = await res.json()
return {
props: { project }
}
}
export default function ProjectPage({ project }) {
return <h1>{project.title}</h1>
}
// ✅ Forma nueva: app/project/[id]/page.tsx
export default async function ProjectPage({ params }) {
const { id } = params
const res = await fetch(`https://api.example.com/projects/${id}`, {
cache: 'no-store' // ¡Clave! Equivale al comportamiento de getServerSideProps
})
const project = await res.json()
return <h1>{project.title}</h1>
}
Parece más limpio, ¿verdad? Pero hay dos trampas grandes.
Trampa 1: caché mal configurada
Por defecto, el fetch de App Router usa caché (equivalente a getStaticProps), no pide datos frescos en cada petición.
La primera vez que migré sin mirar esto, la página de precios no se actualizaba. Los usuarios decían «ya bajó el precio y la web sigue igual»; tardé horas hasta ver que era la caché.
Tabla de equivalencias:
getServerSideProps→cache: 'no-store'getStaticProps→cache: 'force-cache'(comportamiento por defecto)getStaticProps + revalidate→next: { revalidate: 60 }
Trampa 2: ¿y el estado del cliente?
Las páginas con getServerSideProps suelen tener filtrado, ordenación u otra interacción.
En App Router, un async Server Component no puede usar useState, useEffect ni otros hooks.
Solución: separar componentes.
// app/products/page.tsx (Server Component)
export default async function ProductsPage() {
const products = await fetchProducts() // datos en el servidor
return <ProductList initialData={products} /> // pasa al Client Component
}
// components/ProductList.tsx (Client Component)
'use client' // ¡Esta línea!
import { useState } from 'react'
export function ProductList({ initialData }) {
const [products, setProducts] = useState(initialData)
const [filter, setFilter] = useState('')
// lógica de filtrado en el cliente
const filtered = products.filter(p => p.name.includes(filter))
return (
<div>
<input value={filter} onChange={e => setFilter(e.target.value)} />
{filtered.map(p => <ProductCard key={p.id} product={p} />)}
</div>
)
}
El servidor trae los datos; el cliente maneja la interacción. Roles claros.
Cuidado: no abuses de “use client”. He visto páginas enteras marcadas así y se pierde el sentido de Server Components.
Pasos de migración en la práctica
Resumo un flujo en dos fases:
Fase 1: separar componentes
En el directorio pages original, divide «solo presentación» y «con estado»; prueba que todo funciona.
Fase 2: mover a app
- La parte de presentación va a app/[route]/page.tsx, async, con fetch dentro
- La parte con estado va a un archivo aparte con “use client”
- Elimina getServerSideProps
Si algo falla, puedes revertir sin mezclar dos mundos.
Un detalle más
Si leías context.req.cookies para la sesión, ahora es:
import { cookies } from 'next/headers'
export default async function Page() {
const cookieStore = cookies()
const token = cookieStore.get('auth-token')
// con el token, pide datos de usuario...
}
Lo mismo con headers(), redirect(), etc., desde next/headers o next/navigation. La documentación oficial tiene la lista completa.
Siete problemas frecuentes y cómo resolverlos
Aquí va lo importante. Los siete de abajo los viví yo; cada uno me costó al menos una hora de depuración.
Problema 1: errores del servidor ocultos
Síntoma: la página no renderiza, no hay error visible, solo skeleton o blanco.
Mi caso: cambié una llamada a la API y la página quedó en blanco. En consola, nada. Pensé que faltaban datos, añadí console.log… sin suerte.
Al final, el servidor lanzaba una excepción pero, sin error.tsx, Next.js la tragaba y mostraba el fallback de Suspense.
Solución: añade error.tsx en cada segmento de ruta:
// app/dashboard/error.tsx
'use client'
export default function Error({ error, reset }) {
return (
<div>
<h2>Error: {error.message}</h2>
<button onClick={reset}>Reintentar</button>
</div>
)
}
Así al menos ves el mensaje. En desarrollo, Next.js muestra el stack; en producción, un mensaje amigable.
Problema 2: useRouter ya no funciona como antes
Síntoma: useRouter().push() no navega o falla porque falta un método.
Causa: next/router y next/navigation son APIs distintas e incompatibles.
Al principio pensé que bastaba con cambiar el import:
// ❌ Mal
import { useRouter } from 'next/navigation'
const router = useRouter()
router.push('/dashboard') // ¡push no existe!
Luego supe que useRouter de next/navigation no tiene push como en Pages Router; hay funciones aparte:
// ✅ Bien
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
const router = useRouter()
router.push('/dashboard') // en realidad sí existe, pero el comportamiento difiere
// o usa Link directamente
import Link from 'next/link'
<Link href="/dashboard">Ir al panel</Link>
Tabla de equivalencias (la tenía pegada en el monitor):
| Pages Router | App Router |
|---|---|
useRouter().push(url) | useRouter().push(url) (existe, pero no es lo ideal) |
useRouter().pathname | usePathname() |
useRouter().query | useSearchParams() |
useRouter().asPath | usePathname() + useSearchParams() |
Problema 3: importación dinámica que falla
Síntoma: un componente con next/dynamic no renderiza; en consola: «You’re importing a component that needs useState. It only works in a Client Component…»
Causa: Server Component se renderiza en servidor por defecto; librerías solo cliente (gráficos, etc.) revientan.
Tenía una página de gráficos con ECharts:
// ❌ Esto falla
import dynamic from 'next/dynamic'
const Chart = dynamic(() => import('./Chart'), { ssr: false })
export default function Page() {
return <Chart data={data} />
}
El error decía que Chart necesita window, que no existe en el servidor.
Solución: marca page.tsx con “use client”, o extrae Chart a un Client Component:
// app/charts/page.tsx
import { ClientChart } from './ClientChart'
export default function Page() {
return <ClientChart />
}
// app/charts/ClientChart.tsx
'use client'
import dynamic from 'next/dynamic'
const Chart = dynamic(() => import('./Chart'), { ssr: false })
export function ClientChart() {
return <Chart data={data} />
}
Problema 4: parpadeo al cambiar de página
Síntoma: al seguir un enlace, toda la página se re-renderiza; cabecera y barra lateral parpadean.
Causa: layout.tsx mal configurado o sin usar layout.
La ventaja de App Router son los layouts anidados; al principio puse la navegación en cada page.tsx y, claro, parpadeaba todo.
Enfoque correcto:
// app/layout.tsx (layout raíz, compartido)
export default function RootLayout({ children }) {
return (
<html>
<body>
<Header /> {/* cabecera: no se re-renderiza */}
{children}
</body>
</html>
)
}
// app/dashboard/layout.tsx (layout del panel)
export default function DashboardLayout({ children }) {
return (
<div className="flex">
<Sidebar /> {/* barra lateral: estable al cambiar dentro del panel */}
<main>{children}</main>
</div>
)
}
Entre /dashboard/analytics y /dashboard/settings solo se actualiza main; la barra lateral no se mueve.
Problema 5: la página 404 no funciona
Síntoma: no aparece tu 404 personalizado, solo el de Next.js.
Causa: conflicto entre 404.js de Pages Router y not-found.tsx de App Router.
Al migrar, /pages/404.js seguía ahí y /app/not-found.tsx no hacía efecto.
Solución: borra /pages/404.js y /pages/500.js; usa las convenciones de App Router:
// app/not-found.tsx
export default function NotFound() {
return <h1>Página no encontrada</h1>
}
Dispara 404 desde page.tsx:
import { notFound } from 'next/navigation'
export default async function Page({ params }) {
const data = await fetchData(params.id)
if (!data) {
notFound() // dispara 404
}
return <div>{data.title}</div>
}
Problema 6: el servidor de desarrollo se vuelve lento
Síntoma: al arrancar va bien; tras varios cambios, el hot reload tarda 10 segundos o el proceso cae.
Sinceramente: tampoco lo resolví del todo.
Es un problema conocido de Next.js 14. El equipo de FlightControl lo dijo en su blog: «el rendimiento del dev server es tan malo que preferiría renunciar a todas las novedades». Reiniciaban cada 20 minutos.
En nuestro equipo, igual.
Mitigaciones temporales:
- Reinicia el dev server con frecuencia (yo puse un recordatorio cada 15 minutos)
next dev --turbocon Turbopack experimental (más rápido, a veces con bugs)- Menos Server Components donde un Client Component basta
Next.js 15 supuestamente mejora esto; aún no lo he probado en profundidad.
Problema 7: librerías de terceros incompatibles
Síntoma: Framer Motion, Lottie u otras animaciones fallan: no encuentran window o document.
Causa: son librerías solo cliente; no pueden vivir en Server Component.
Usaba Framer Motion para transiciones; tras migrar, todo roto.
Solución:
- Envuelve con “use client” los componentes que usan esas librerías
- Comprueba si hay versión compatible con React 18
- Si no hay remedio, cambia a una librería con mejor soporte SSR
Librerías típicamente solo cliente:
- Framer Motion (animaciones de salida en App Router: debates abiertos en issues)
- swiper, slick-carousel y carruseles similares
- ECharts, Chart.js y gráficos
- react-dnd, dnd-kit y arrastre
Si tu proyecto depende mucho de ellas, revisa issues en GitHub antes de migrar.
Optimización tras la migración
Migrar no es el final; aún hay margen.
Reducir JavaScript en el cliente
Es la gran ventaja de Server Components.
Nuestra lista de productos tenía ~120 KB de React (gzip). Tras migrar, la presentación pasó a Server Component y solo filtrado/ordenación quedó en cliente: el bundle bajó a 45 KB.
Cómo comprobarlo:
npm run build
En la salida, mira qué páginas son (Static) o (SSR) y cuáles llevan ○ (Client Component). Si todo es ○, probablemente abusaste de “use client”.
Consejos:
- Contenido estático (texto, imágenes) en Server Component
- Formularios y botones en Client Component
- No marques toda la página con “use client”; solo los hijos que lo necesiten
Usar la caché con criterio
La estrategia de caché en App Router es más rica que en Pages Router.
// Sin caché: datos en tiempo real
fetch(url, { cache: 'no-store' })
// Caché 60 s y revalidación (actualizaciones frecuentes pero no instantáneas)
fetch(url, { next: { revalidate: 60 } })
// Caché permanente (datos estáticos)
fetch(url, { cache: 'force-cache' })
Nuestra lista de productos usa revalidate de 60 segundos: datos razonablemente frescos y menos carga en el servidor. Tras el despliegue, las llamadas a la API bajaron un 60 %.
Monitorizar rendimiento
Compara antes y después:
- FCP (First Contentful Paint) — cuándo el usuario ve el primer contenido
- TTI (Time to Interactive) — cuándo la página es totalmente interactiva
- CLS (Cumulative Layout Shift) — si el layout salta al cargar
Con Vercel Analytics vimos FCP de 3,2 s a 1,8 s y TTI de 5,1 s a 3,3 s.
No todas las páginas mejoran. En el editor de lienzo, casi sin cambio.
Cuidado con optimizar de más
No partas componentes solo para subir el porcentaje de Server Component.
Una vez partí un formulario en 20 trozos «para maximizar Server Components». La legibilidad empeoró, el equipo se perdió y el coste de mantenimiento subió.
Regla práctica: si un componente necesita useState/useEffect, márcalo “use client” y sigue. Server Components son una herramienta, no un KPI.
Conclusión
Resumen de ideas clave:
Migrar no es moda, es resolver problemas reales. Si necesitas layouts anidados, menos JS en el cliente o mantenimiento largo, App Router merece el esfuerzo.
Elige bien la estrategia: gradual en proyectos pequeños; sin downtime en los grandes. No mezcles migración con features nuevas.
Tropezar es normal; estos siete problemas son la punta del iceberg. Busca en GitHub: el 90 % ya lo vivió alguien.
No optimices en exceso. La legibilidad y la velocidad del equipo importan más que el tamaño del bundle.
Mi consejo: empieza con 1-2 páginas piloto, documenta el flujo y luego escala. Nosotros: 3 días la primera página; 5 días las diez siguientes.
Next.js App Router tiene fallos (sobre todo el dev server), pero la dirección es correcta. Con la madurez del ecosistema, muchas trampas se irán cerrando.
Si te atascas en la migración, comenta: quizá ya pasé por el mismo sitio.
Recursos relacionados:
- Guía oficial de migración de Next.js
- Migración sin downtime de WorkOS
- Preguntas frecuentes de App Router (GitHub Discussions)
¡Buena migración!
Flujo completo de migración de Next.js Pages Router a App Router
Pasos completos de evaluación a producción, con elección de estrategia y solución de problemas frecuentes
⏱️ Estimated time: 80 hr
- 1
Step 1: Evaluar si el proyecto merece migrar
Criterios de decisión:
• Necesidad de layouts anidados: varios niveles de layout sin re-renderizar al cambiar de página
• Margen de optimización: tiempo de carga inicial superior a 3 segundos con margen de mejora
• Mantenimiento a largo plazo: proyecto con más de 3 años de vida; migrar pronto aprovecha antes las ventajas
Escenarios en los que no conviene migrar:
• El proyecto va a cerrarse pronto
• Sitio estático pequeño (menos de 5 páginas)
• El equipo no domina React 18
• Dependencia de muchas librerías de terceros antiguas - 2
Step 2: Elegir la estrategia de migración
Según el tamaño del proyecto:
Proyecto pequeño (<10 páginas, páginas independientes) → Migración gradual:
• Una página cada vez
• Se acepta un estado de carga al cambiar entre routers
• Adecuado para blogs y proyectos con bajo acoplamiento entre páginas
Proyecto grande (>10 páginas, alta exigencia de UX) → Migración sin downtime:
• Reconstruir todas las páginas en /app/new
• Controlar la versión con rewrites + parámetro de consulta
• Pasar a producción cuando las pruebas internas estén listas - 3
Step 3: Migrar getServerSideProps
Pasos:
1. Convierte el componente de página en función async
2. Obtén los datos directamente dentro del componente
3. Configura la caché correcta:
• getServerSideProps → cache: 'no-store'
• getStaticProps → cache: 'force-cache'
• getStaticProps + revalidate → next: { revalidate: 60 }
4. Separa la interacción del cliente en Client Component:
• El servidor obtiene los datos y los pasa al Client Component
• El Client Component maneja useState, useEffect y la lógica interactiva - 4
Step 4: Actualizar rutas y navegación
Actualiza el código relacionado con rutas:
• next/router → next/navigation
• useRouter().pathname → usePathname()
• useRouter().query → useSearchParams()
• Usa el componente Link en lugar de router.push()
Nota: useRouter de next/navigation se comporta distinto al de Pages Router; conviene usar Link directamente - 5
Step 5: Configurar el sistema de layouts
Aprovecha los layouts anidados para evitar parpadeos al cambiar de página:
• Crea app/layout.tsx como layout raíz (Header, Footer)
• Crea sublayouts por zona funcional (p. ej. app/dashboard/layout.tsx)
• Cada layout solo añade los elementos de UI propios de ese nivel
• Los sublayouts heredan el padre automáticamente y no se re-renderizan al cambiar de página - 6
Step 6: Gestionar errores y 404
Manejo de errores:
• Crea error.tsx para capturar errores y mostrar un mensaje amigable
• Marca el componente error con 'use client'
Manejo de 404:
• Elimina /pages/404.js
• Crea app/not-found.tsx
• Usa notFound() en page.tsx para disparar el 404 - 7
Step 7: Probar y optimizar
Puntos de prueba:
• Comprueba que todas las rutas funcionan
• Verifica que la obtención de datos es correcta
• Revisa que la interacción del cliente funciona
• Confirma que el cambio de layout no parpadea
Optimización de rendimiento:
• Reduce el uso innecesario de 'use client'
• Usa estrategias de caché con criterio
• Monitoriza FCP, TTI, CLS y otras métricas
• Compara el rendimiento antes y después de la migración
FAQ
¿Cuál es la diferencia entre migración gradual y migración sin downtime?
La migración sin downtime reconstruye todas las páginas en /app/new y usa un parámetro de consulta para cambiar de versión; cuando las pruebas pasan, se pasa a producción. Es mejor para proyectos grandes con alta exigencia de UX.
¿Cómo se obtienen los datos tras migrar getServerSideProps?
Configura bien la caché:
• getServerSideProps → cache: 'no-store'
• getStaticProps → cache: 'force-cache'
Si la página tiene interacción del cliente, sepárala en Server Component (datos) y Client Component (interacción).
¿Por qué parpadea la página al cambiar de ruta tras la migración?
¿Cómo se usa useRouter en App Router?
¿Qué hacer si una librería de terceros no es compatible tras la migración?
Librerías frecuentemente incompatibles:
• Framer Motion
• Librerías de gráficos (ECharts, Chart.js)
• Carruseles y similares
Antes de migrar, revisa los issues de GitHub de la librería para confirmar compatibilidad.
¿Cómo solucionar que el servidor de desarrollo vaya más lento?
Soluciones temporales:
• Reinicia el dev server con regularidad (cada 15 minutos, por ejemplo)
• Usa next dev --turbo para activar Turbopack
• Reduce Server Components innecesarios
Next.js 15 supuestamente mejora este punto.
¿Cuánto tiempo lleva la migración?
• Proyecto pequeño (<10 páginas): 3-5 días
• Proyecto grande: 2-3 semanas
Empieza con 1-2 páginas piloto, valida el flujo y luego escala. En nuestro equipo, la primera página tardó 3 días; las 10 siguientes, solo 5.
15 min de lectura · Publicado el: 18 dic 2025 · Actualizado el: 21 ago 2026
Guía completa de Next.js
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Next.js 15 en la práctica: cómo monté un blog de nivel producción en un fin de semana
Con un caso real de Next.js 15 + Server Actions + Prisma, te guío paso a paso para montar un blog full stack de nivel producción en un fin de semana. Incluye código completo, lecciones aprendidas y estrategias de optimización de rendimiento.
Parte 2 de 51
Siguiente
Next.js: rutas avanzadas en la práctica — grupos, layouts anidados, rutas paralelas e interceptadas
Guía completa de las cuatro rutas avanzadas de Next.js: grupos de rutas para directorios claros, layouts anidados reutilizables, rutas paralelas para mostrar varias páginas a la vez e interceptadas para modales elegantes. Con ejemplos de código y trampas a evitar.
Parte 4 de 51



Comentarios
Inicia sesión con GitHub para dejar un comentario