App Router de Next.js: Qué cambia frente al Pages Router

An IT professional configuring network cables in a server rack, focusing on Ethernet connections.
Foto de Field Engineer en Pexels

En Next.js 13 llegó el App Router, una forma nueva de organizar y renderizar tus páginas. Aunque el Pages Router sigue funcionando, hay diferencias estructurales y de comportamiento que conviene conocer si vas a iniciar un proyecto o migrar una aplicación existente.

Estructura de carpetas

Con el Pages Router todo se basa en la carpeta pages/. Cada archivo .js/.tsx representa una ruta y los subdirectorios generan rutas anidadas. En el App Router la convención cambia a app/, donde cada carpeta representa una ruta y dentro puedes colocar varios archivos con roles específicos: page.tsx, layout.tsx, loading.tsx, error.tsx, etc.

app/
 ├─ dashboard/
 │   ├─ layout.tsx
 │   ├─ page.tsx
 │   └─ loading.tsx
 └─ page.tsx   // / (home)

Esta separación permite que el layout se comparta automáticamente entre todas las sub‑rutas y que los estados de carga o error estén ligados a cada segmento de la ruta.

Routing y layout anidados

En el Pages Router los layouts se gestionan con componentes de orden superior o mediante _app.js. Con el App Router los layouts son archivos layout.tsx que se anidan de forma natural: el layout de dashboard/ envuelve a dashboard/page.tsx y, a su vez, hereda del layout raíz definido en app/layout.tsx. Esto reduce la necesidad de lógica extra para envolver componentes.

  • Los layouts pueden ser server components o client components según añadas "use client".
  • Los loading.tsx y error.tsx se activan automáticamente mientras se resuelven datos o ocurre un error.

Obtención de datos (data fetching)

En Pages Router la obtención de datos se hacía en getStaticProps, getServerSideProps o dentro de componentes cliente con useEffect. El App Router simplifica este proceso: cualquier page.tsx o layout.tsx puede ser una función async que devuelva JSX, y el framework se encarga de ejecutar la lógica en el servidor antes de renderizar.

// app/dashboard/page.tsx
export default async function DashboardPage() {
  const res = await fetch('https://api.example.com/stats', { cache: 'no-store' });
  const data = await res.json();

  return (
    <section>
      <h1>Estadísticas</h1>
      <p>Visitantes: {data.visitors}</p>
    </section>
  );
}

Observa cómo el código sigue siendo JSX, pero la función es async y el fetch se ejecuta en el servidor por defecto.

Server Components por defecto

Una de las ideas centrales del App Router es que los componentes son server components a menos que declaren "use client". Esto permite acceder a recursos del servidor (bases de datos, APIs secretas) sin enviar código al cliente, reduciendo el bundle y mejorando la performance. En Pages Router, cada página se renderizaba en el cliente o en el servidor según la estrategia elegida, pero nunca había esta distinción granular por archivo.

Transiciones y UI de carga

Next.js 13 introdujo next/link con soporte para transiciones de página. Cuando utilizas el App Router, los loading.tsx aparecen mientras se resuelven los datos del segmento activo, creando una experiencia más fluida sin tener que gestionar estados de carga manualmente. En Pages Router debías crear estados loading en tus componentes o usar librerías externas.

¿Cuándo migrar?

Si estás iniciando un proyecto nuevo, el App Router es la opción recomendada: te brinda una arquitectura más modular y aprovecha las últimas mejoras de React (server components, streaming). Si tu aplicación actual está estable con Pages Router y no necesitas las funcionalidades avanzadas, la migración puede esperar; el soporte seguirá vigente al menos durante la próxima versión mayor.

En cualquier caso, la decisión depende de la complejidad de tu proyecto y del tiempo que puedas invertir en adaptar la estructura de carpetas. Lo importante es entender que el App Router no es sólo un cambio de nombre, sino una revisión profunda de cómo Next.js maneja el rendering, la carga de datos y los layouts.

¡Experimenta creando una pequeña ruta con app/hello/page.tsx y observa cómo desaparecen los archivos getStaticProps! Verás que la experiencia de desarrollo se vuelve más directa y el código más limpio.