Next.js Routing: Domina el App Router y las rutas dinámicas como un Pro
desarrollo desarrollo, js, nextjs, routerEl sistema de rutas de Next.js es su superpoder. 🚀 Aprende a organizar tu proyecto profesionalmente y a manejar URLs dinámicas sin dolor de cabeza
1. Introducción: La Evolución del Routing en Next.js (2026)
En 2026, el App Router se ha consolidado como el estándar en Next.js para la gestión de rutas, superando al Pages Router. Sus principales ventajas son:
- Rendimiento Superior: Gracias a los Server Components.
- Escalabilidad Sin Precedentes: Adecuado para proyectos de cualquier tamaño.
- Mejor Experiencia de Desarrollo: Simplifica la organización y el mantenimiento del código.
Las rutas dinámicas son cruciales para manejar grandes volúmenes de contenido (blogs, tiendas online) permitiendo generar miles de páginas únicas a partir de un único componente. Este artículo detalla el App Router y las rutas dinámicas, desde lo básico hasta técnicas avanzadas.
2. Entendiendo el App Router: La Estructura de Carpetas es tu Mapa
El App Router se basa en un sistema de ficheros intuitivo para estructurar aplicaciones Next.js.
Fundamentos del Routing Basado en Ficheros
- Carpeta
/app: Es la raíz de todas las rutas. Su estructura de directorios mapea directamente a los segmentos de la URL.- Ejemplo:
app/dashboard/settings/page.tsxse traduce a la URL/dashboard/settings.
- Ejemplo:
- Colocación de Código: Permite agrupar archivos de ruta (
page.js), UI específica (layout.js) y lógica relacionada dentro de la misma carpeta de ruta, mejorando la organización.
Archivos Especiales para Definir UI y Comportamiento
Dentro de cada segmento de ruta, se utilizan nombres de archivo específicos:
page.js(o.tsx): Define la UI única para un segmento de URL específico.layout.js(o.tsx): Comparte UI entre múltiples rutas (ej. navegación, pie de página). Envuelve lospage.jsy otros layouts anidados como sus bloques hijos (children).- Otros archivos especiales:
loading.js: Muestra UI de carga.error.js: Define UI de error.not-found.js: Muestra una página 404 personalizada.route.js: Crea API endpoints (reemplazapages/api).
Organización Avanzada de Rutas
- Rutas Anidadas: Subcarpetas dentro de
appcrean jerarquías de URL (ej.app/dashboard/analytics/page.tsxpara/dashboard/analytics). - Grupos de Rutas
(carpeta): Permiten organizar rutas lógicamente sin afectar la URL (ej.app/(marketing)/about/page.tsxse mapea a/about). Útil para agrupar secciones como marketing, autenticación, etc. - Carpetas Privadas
_carpeta: Archivos y carpetas que comienzan con_no son ruteables. Útiles para componentes, utilidades o estilos específicos de una ruta.
3. Rutas Dinámicas: Creando Páginas Flexibles con [slug]
Las rutas dinámicas permiten que un único patrón de ruta maneje múltiples URLs, ideal para contenido variable.
¿Qué son las Rutas Dinámicas?
Segmentos de URL que actúan como placeholders o variables. Permiten generar miles de páginas desde una única plantilla.
- Ejemplos:
blog/[slug]/page.tsxmaneja/blog/mi-post-genial,/blog/otro-articulo.
Definiendo Segmentos Dinámicos con Corchetes []
Se definen encerrando el nombre de la variable entre corchetes en el nombre de la carpeta.
- Sintaxis:
[id],[slug],[userId]. - Ejemplo:
app/blog/[slug]/page.tsxcaptura el identificador único del post en la URL.
Accediendo a los Parámetros Dinámicos (params)
- En Server Components (por defecto): Los parámetros se reciben como una prop
paramsenpage.tsxolayout.tsx.// app/blog/[slug]/page.tsx interface PostPageProps { params: { slug: string; }; } export default function PostPage({ params }: PostPageProps) { // params.slug contiene el valor del segmento dinámico (ej. "mi-post-genial") // Se puede usar para data fetching en el servidor. return ( <main> <h1>Leyendo el artículo: {params.slug}</h1> <p>Contenido generado dinámicamente.</p> </main> ); } - En Client Components: Se utiliza el hook
useParamsdenext/navigation.// app/blog/[slug]/components/PostInteraction.tsx 'use client'; import { useParams } from 'next/navigation'; export default function PostInteraction() { const params = useParams<{ slug: string }>(); const { slug } = params; return <p>Interactuando con el post: {slug}</p>; }
Rutas “Catch-all” [...slug]
Capturan múltiples segmentos de URL en un solo parámetro, recibido como un array de cadenas.
- Sintaxis:
[...slug]. - Ejemplo:
app/docs/[...path]/page.tsxpara/docs/features/app-routerdondeparams.pathsería['features', 'app-router'].
Rutas “Catch-all” Opcionales [[...slug]]
Permiten que el segmento dinámico catch-all sea opcional.
- Sintaxis:
[[...slug]]. - Ejemplo:
app/shop/[[...categorySlug]]/page.tsxcoincide con/shop(dondeparams.categorySlugesundefined) y/shop/electronics(dondeparams.categorySluges['electronics']).
Pre-renderizado de Rutas Dinámicas con generateStaticParams
Permite pre-renderizar páginas dinámicas en tiempo de construcción (SSG) para mejorar el rendimiento y el SEO.
- Función
generateStaticParams: Se define en el archivopage.tsxy retorna un array de objetos, cada uno definiendo losparamspara una instancia pre-renderizada.// app/blog/[slug]/page.tsx export async function generateStaticParams() { const posts = await fetch('https://api.example.com/posts').then((res').then((res) => res.json()); return posts.map((post: { slug: string }) => ({ slug: post.slug, })); }
4. params vs. searchParams: Entendiendo los Datos de la URL
params(Parámetros de Ruta Dinámica):- Parte integral de la URL (ej.
/blog/mi-titulo). - Definidos por la estructura de carpetas con
[]. - Identifican recursos específicos.
- Parte integral de la URL (ej.
searchParams(Parámetros de Consulta URL):- Opcionales, aparecen después del
?(ej.?filtro=activo&pagina=2). - Usados para filtrar, ordenar, paginar, etc., sin cambiar la ruta base.
- Opcionales, aparecen después del
Accediendo a searchParams
- En Server Components: Se reciben como una prop
searchParamsenpage.tsx.// app/productos/page.tsx interface ProductsPageProps { searchParams: { category?: string; sort?: string; }; } export default function ProductsPage({ searchParams }: ProductsPageProps) { const { category, sort } = searchParams; // Usar category, sort para filtrar/paginar productos. return <main><h1>Productos</h1><p>Categoría: {category || 'Todas'}</p></main>; } - En Client Components: Se utiliza el hook
useSearchParamsdenext/navigation.// app/productos/components/FilterComponent.tsx 'use client'; import { useSearchParams } from 'next/navigation'; export default function FilterComponent() { const searchParams = useSearchParams(); const currentCategory = searchParams.get('category'); return <p>Filtro actual: {currentCategory || 'Ninguno'}</p>; }
Combinando params y searchParams
Una página puede recibir ambas props para identificar un recurso y aplicar filtros.
- Ejemplo:
app/tienda/[productId]/page.tsxpuede recibirparams.productIdysearchParams.variant.
5. Layouts vs. Pages: Organizando la UI y Optimizando la Carga
- Page (
page.js/page.tsx):- Define el contenido único y final de una URL específica.
- Se re-renderiza completamente en cada navegación de página.
- Layout (
layout.js/layout.tsx):- Define UI compartida para una ruta y sus hijos.
- Renderizado Parcial: No se recarga ni re-renderiza en navegación entre páginas hijas que comparten el mismo layout. Preserva el estado de React en el cliente.
- El
Root Layout(app/layout.js) es obligatorio y envuelve toda la aplicación (<html>,<body>). - Los layouts anidados heredan UI de sus padres.
- Deben renderizar una prop
children.
6. Server Components por Defecto: ¿Por qué tu Web “Vuela” en 2026?
Los Server Components (Componentes de Servidor) son el modelo de renderizado por defecto en el App Router.
Beneficios Clave
- Menor JavaScript en el Cliente: Reduce el tamaño del bundle, acelerando la carga inicial.
- Mejora del Rendimiento Inicial (FCP, LCP): Renderizado más rápido del HTML.
- SEO Optimizado: HTML completamente renderizado en el servidor para fácil indexación.
- Acceso Directo a Backend y Bases de Datos: Simplifica la lógica de data fetching y mejora la seguridad al no exponer credenciales.
- Data Fetching Eficiente y Caching: La API
fetchextendida de Next.js ofrece deduplicación y caché automática. Menor latencia de red. - Streaming y Renderizado Progresivo: Envío de HTML en chunks para que el usuario vea contenido antes de la carga completa. Uso de
<Suspense>para componentes de carga.
Cuándo Usar Client Components ('use client')
Se utilizan para interactividad del lado del cliente:
- Manejo de estado de React (
useState). - Hooks de ciclo de vida (
useEffect). - Manejo de eventos del navegador.
- Acceso al DOM o APIs del navegador.
- Librerías que dependen del navegador.
7. Ejemplo Práctico Integrado: Blog Dinámico
Implementación de un blog con lista de posts y páginas de detalle dinámicas.
Estructura del Proyecto:
app/
├── layout.tsx
└── blog/
├── page.tsx # Lista de posts
└── [slug]/ # Ruta dinámica para posts individuales
└── page.tsx # Página de detalle del post
Implementación de app/blog/[slug]/page.tsx:
// app/blog/[slug]/page.tsx
interface Post {
slug: string;
title: string;
content: string;
}
interface PostPageProps {
params: {
slug: string;
};
}
// Simulación de base de datos/API
const posts: Post[] = [
{ slug: 'mi-primer-post', title: 'Mi Primer Post en Next.js App Router', content: 'Este es el contenido de mi primer post.' },
{ slug: 'rutas-dinamicas-a-fondo', title: 'Rutas Dinámicas a Fondo con Next.js 14', content: 'Profundizando en cómo crear rutas flexibles.' },
{ slug: 'server-components-el-futuro', title: 'Server Components: El Futuro de la Web Performance', content: 'Descubre cómo los Server Components transforman el rendimiento.' },
];
async function getPostBySlug(slug: string): Promise<Post | undefined> {
return posts.find(post => post.slug === slug);
}
// Pre-renderiza páginas para cada post en tiempo de construcción
export async function generateStaticParams() {
return posts.map(post => ({
slug: post.slug,
}));
}
export default async function PostPage({ params }: PostPageProps) {
const { slug } = params;
const post = await getPostBySlug(slug); // Data fetching en el servidor
if (!post) {
return <main><h1>404 - Post no encontrado</h1></main>;
}
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
<div>Slug: {slug}</div>
</main>
);
}
Este componente es un Server Component que accede a params.slug para buscar datos y renderizar el contenido. generateStaticParams optimiza el rendimiento para posts conocidos.
8. Conclusión: Preparando tu Aplicación Next.js para el Futuro
El App Router y las rutas dinámicas de Next.js, junto con los Server Components por defecto, son herramientas esenciales para construir aplicaciones web modernas, eficientes y escalables. La estructura de carpetas intuitiva, la gestión de params y searchParams, y la distinción entre layouts y pages optimizan la UI y la carga. Dominar estos conceptos permite crear aplicaciones con rendimiento superior, experiencia de usuario fluida y SEO mejorado.