App Router de Next.js: qué cambia frente a Pages Router

Detailed close-up of ethernet cables and network connections on a router, showcasing modern technology.
Foto de Pixabay en Pexels

Desde la versión 13, Next.js introdujo el App Router, una forma más flexible y moderna de organizar nuestras rutas. Si ya trabajas con el tradicional Pages Router, es normal que te surjan dudas: ¿qué ha cambiado realmente? ¿Vale la pena migrar? En este artículo repasamos los puntos clave y te damos una guía práctica para dar el salto.

1. Estructura de archivos y convenciones

El Pages Router se basa en la carpeta pages/. Cada archivo .js o .tsx representa una ruta y el nombre del archivo define la URL. Con el App Router la carpeta principal es app/ y, además de las páginas, puedes crear layout.js, page.js y loading.js dentro de cualquier sub‑directorio.

<pre><code>app/
  dashboard/
    layout.js   // Layout compartido para el dashboard
    page.js     // /dashboard
    settings/
      page.js   // /dashboard/settings
  page.js       // / (home)
</code></pre>

Esta jerarquía permite definir layouts anidados que se renderizan automáticamente según la ruta, algo que con pages/ requería componentes de alto nivel y lógica extra.

2. Server Components por defecto

En el App Router, los archivos page.js y layout.js son Server Components a menos que exportes 'use client' al inicio del archivo. Esto significa que el código se ejecuta en el servidor y solo envía HTML al cliente, reduciendo el bundle y mejorando el TTFB. Con el Pages Router, los componentes siempre eran client‑side a menos que usaras getServerSideProps o getStaticProps.

3. Data fetching simplificado

En el nuevo router, puedes obtener datos directamente dentro de la función del componente con async. No necesitas getStaticProps ni getServerSideProps:

<pre><code>export default async function Page(){
  const res = await fetch('https://api.example.com/posts')
  const posts = await res.json()
  return (
    <ul>
      {posts.map(p=><li key={p.id}>{p.title}</li>)}
    </ul>
  )
}
</code></pre>

El fetch se ejecuta en el servidor, el HTML resultante llega ya con los datos y el cliente no necesita una llamada extra.

4. Middleware y rutas protegidas

El App Router introduce la carpeta middleware.js a nivel de app/. Puedes colocar lógica de autenticación que se ejecuta antes de cada request, sin necesidad de envolver cada página en un HOC. Además, las rutas pueden marcarse como segment config para forzar dynamic = 'force-static' o revalidate directamente.

5. Migración paso a paso

  • 1. Crea la carpeta app/: Copia la estructura básica y deja la carpeta pages/ temporalmente para ir migrando página a página.
  • 2. Convierte una página sencilla: Mueve pages/about.js a app/about/page.js. Añade 'use client' solo si necesita estado o efectos.
  • 3. Añade layouts: Si tienes un header/footer común, crea app/layout.js y envuelve {children}. Los layouts anidados se crean dentro de sub‑directorios.
  • 4. Refactoriza la carga de datos: Sustituye getStaticProps por funciones async dentro del componente. Elimina export async function getStaticProps.
  • 5. Prueba y elimina pages/: Cuando todas las rutas críticas estén en app/, puedes borrar la carpeta pages/ y ajustar los imports.

6. Cosas a tener en cuenta

El App Router todavía está en evolución; algunas APIs, como next/link y next/navigation, tienen ligeras diferencias. Además, los edge functions funcionan de forma nativa con los nuevos layouts, lo que abre posibilidades para caching inteligente y personalización a nivel de CDN.

En resumen, el App Router aporta una arquitectura más declarativa, reduce la cantidad de código necesario para cargar datos y permite aprovechar al máximo los Server Components. Si estás iniciando un proyecto nuevo, elige app/ desde el principio. Si ya tienes una base con pages/, la migración es gradual y, una vez completada, notarás mejoras en rendimiento y mantenibilidad.

¿Te animas a probarlo? Comparte tus dudas en los comentarios y seguimos aprendiendo juntos.