Next.js — Páginas, Rutas estáticas, dinámicas y anidadas
## Páginas con Next.js
_Next.js_ utiliza **enrutamiento** **basado** en el **sistema** de **archivos** , lo que significa que puedes usar **carpetas y archivos para definir rutas**.
Una **página** en _Next.js_ representa una interfaz de usuario que se renderiza en una ruta específica del sitio [ref].
Para crear una página, debes agregar un archivo `page.tsx` dentro del directorio `/app` y exportar un componente de React.
export default function ExamplePage() {
return <h1>Esta es una página de ejemplo en Next.js!</h1>;
}
> **Nota** : El proyecto genera una página por default en `_/app`
### Crear una página
Para crear una página nueva en Next.js, debes tener en cuenta los siguientes pasos:
* Crear una carpeta con el nombre de la ruta deseada
* Dentro de esa carpeta, crea un archivo llamado `page.tsx`
* Exporta un componente de React por defecto.
Vamos a crear una página que va a estar disponible desde la ruta `http://localhost:3000/about`
Crea la carpeta y el archivo:
src/app/about/page.tsx
Dentro de `page.tsx` :
// src/app/about/page.tsx
export default function AboutPage() {
return (
<div className="p-4">
<h1 className="text-2xl font-bold">Acerca de Nosotros</h1>
<p>Esta es la página de información general.</p>
</div>
);
}
Al iniciar el servidor (`npm run dev`), podrás acceder a esta página visitando:
http://localhost:3000/about
> **Descarga el proyecto actual [ref] (branch: simple-page)**
## Rutas en Next.js
En _Next.js_ , cada **carpeta** dentro de `/app` **representa una ruta** de la aplicación.
### Rutas estáticas
Son páginas cuyas **rutas no cambian** , están definidas. Por ejemplo: `/, /about, /contact, /faq, /ssg, etc.`
#### Ventajas de las rutas estáticas:
* SEO: Como son conocidas, se pueden generar como HTML estático.
* Pueden ser renderizadas con SSG (build), por lo que su carga será mucho más rápida.
* Al ser estáticas no aceptan parámetros externos como las rutas dinámicas.
#### ¿Cómo se crean?
Las rutas _estáticas_ se crean exactamente igual que una página:
* Crear una carpeta con el nombre de la ruta deseada
* Dentro de esa carpeta, crea un archivo llamado `page.tsx`
* Exporta un componente de React por defecto.
#### ¿Cómo funcionan?
_Next.js_ con **App Router** analiza la carpeta `/app` y genera automáticamente las rutas, es decir al ejecutar `npm run dev`, _Next.js_ hace lo siguiente:
* Mapea todas las carpetas que estén dentro de `/app` y tengan el archivo `page.tsx` como rutas.
* Genera el HTML y JavaScript necesario.
* Decide si renderiza como **CSR** (cliente), **SSR** (tiempo real), **SSG** (build) o según como hayas escrito el código.
> **Nota** : Los tipos de renderización los vamos a revisar a fondo más adelante.
#### Ejemplo
src/app/contact/page.tsx → /contact
// src/app/contact/page.tsx
export default function ContactPage() {
return (
<div className="p-4">
<h1 className="text-2xl font-bold">Contáctanos!!</h1>
<p>
Estamos para ayudarte :). Escríbenos si tienes alguna duda o sugerencia.
</p>
</div>
);
}
Al iniciar el servidor (`npm run dev`), podrás acceder a esta página visitando:
http://localhost:3000/contact
### Rutas estáticas anidadas
Las rutas estáticas anidadas no son otra cosa que un ruta estática que se encuentra **dentro de otra carpeta estática**. Es decir, representa un **nivel jerárquico más profundo**. Ejemplo: `products/mens, products/woman, docs/getting-started, etc`.
#### Ventajas de las rutas estáticas
* Permite estructurar la app por secciones y subsecciones de forma clara y escalable.
* La URLs son predecibles y amigables para motores de búsqueda (SEO-friendly).
* Puedes tener layouts anidados para compartir diseño entre rutas relacionadas.
* Ideal para secciones grandes con multiples páginas y subsecciones (`/docs/..., /products/..., etc`)
#### ¿Cómo funcionan?
_Next.js_ con **App Router** analiza la carpeta `/app` y genera automáticamente las rutas:
* Mapea todas las carpetas y subcarpetas que estén dentro de `/app`.
* Cada carpeta representa **una parte del path en la URL**.
* Solo **considera** una carpeta como parte de una **ruta si _co-localiza_** archivos especiales, el resto las ignora.
#### Ejemplo:
src/app/dashboard/settings/page.tsx → /dashboard/settings
// src/app/dashboard/settings/page.tsx
export default function SettingsPage() {
return (
<div className="p-4">
<h1 className="text-2xl font-bold">Configuración</h1>
<p>Ajusta tus preferencias...</p>
</div>
);
}
Al iniciar el servidor (`npm run dev`), podrás acceder a esta página visitando:
http://localhost:3000/dashboard/settings
> **Descarga el proyecto actual [ref] (branch: static-routes)**
Ahora intenta acceder a:
http://localhost:3000/dashboard
Podrás observar el mensaje de error: `404 | This page could not be found.`
El comportamiento se le conoce como **_colocation_** [ref], lo que significa que **Next.js solo genera una ruta si la carpeta contiene archivos relevantes** (`page.tsx` o `route.tsx`) **para esa ruta**. Así evita que carpetas vacías generen rutas innecesarias.
Aunque la estructura está definida a través de carpetas, **una ruta no es accesible públicamente** hasta que se agrega un archivo especial.
La ruta se hace pública cuando devuelve una `page.tsx` o `route.tsx`
Si una carpeta **no contiene ninguno de los archivos especiales** que Next.js reconoce, será **ignorada automáticamente** y **no generará una ruta**.
Esto ayuda a evitar errores y asegura que **solo las carpetas válidas se conviertan en rutas accesibles**.
> **Nota** : Aunque es posible colocar archivos no especiales (como componentes, estilos, funciones utilitarias o peticiones API) dentro del directorio `/app`, **no se recomienda hacerlo**. Como buena práctica, se sugiere mantener estos elementos **fuera del directorio** `/app`, en carpetas como `/components`, `/lib`, `/styles`, etc., para mantener una estructura modular, limpia y más fácil de mantener.
### Rutas dinámicas
Son páginas que **dependen** de un **parámetro** **variable** , como un ID o un nombre. Por ejemplo `/posts/1, /users/mau, /products/abc123, etc`.
#### Ventajas de las rutas dinámicas
* Flexibilidad para representar contenido variable.
* Evitar duplicar código ya que no es necesario hacer una página por ítem.
* Escalabilidad total ya que a medida que la app crece, las rutas dinámicas escalan automáticamente sin necesidad de crear archivos nuevos.
* Soporte completo para SSR (contenido cambia frecuentemente), SSG (datos que no cambian) o CSR (necesitas JS del lado del cliente).
* Libertad total para optimizar rendimiento, SEO y experiencia de usuario, según el caso.
#### ¿Cómo se crean?
Las rutas dinámicas se crean de forma muy similar a una ruta estática, con la diferencia de que la carpeta usa corchetes `[foldername]` para definir un parámetro dinámico.
* Crear una carpeta con el nombre de la ruta deseada, nombrandola entre corchetes `[foldername]`.
* Dentro de esa carpeta, crea un archivo llamado `page.tsx`.
* Exporta un componente de React por defecto.
* Accede al parámetro dinámico desde `params` en el componente de página.
#### ¿Cómo funcionan?
Next.js con **App Router** analiza la carpeta `/app` y genera automáticamente las rutas:
* Mapea todas las carpetas que estén dentro de `/app` y tengan el archivo `page.tsx` como rutas.
* Genera el HTML y JavaScript necesario.
* Decide si renderiza como CSR (cliente), SSR (tiempo real), SSG (build) o según como hayas escrito el código.
Cuando el usuario visita una página dinámica (`/posts/5`), Next.js hace lo siguiente:
* Detecta que `[id]` es una ruta dinámica.
* Extrae el `5` como parámetro `params.id`.
* Ejecuta la lógica dentro del componente y renderiza la página.
#### Ejemplo
src/app/posts/[id]/page.tsx → /posts/:id
// src/app/posts/[id]/page.tsx
interface PageParams {
id: string;
}
// La propiedad params es asincrona, por lo que se debe de tratar como promesa
interface PageProps {
params: Promise<PageParams>;
}
export default async function PostPage({ params }: PageProps) {
// Desestructuramos el id de params, ya que es una promesa
const { id } = await params;
return (
<div className="p-4">
<h1 className="text-2xl font-bold">{id}</h1>
</div>
);
}
> **Nota** : En versiones anteriores a la **14** , la propiedad `params` es **síncrona**.
>
> Aunque Next.js **15** aún mantiene compatibilidad con este comportamiento, **se recomienda utilizar** `params` **de forma asíncrona.** Ya que el comportamiento síncrono será eliminado en futuras versiones.
Al iniciar el servidor (`npm run dev`), podrás acceder a esta página visitando:
http://localhost:3000/post/uno
app/posts/[id]/page.js → /posts/a → { id: 'a' }
app/posts/[id]/page.js → /posts/b → { id: 'b' }
app/posts/[id]/page.js → /posts/3 → { id: '3' }
### Rutas dinámicas anidadas
Next.js permite tener en una ruta diferentes niveles dinámicos. Por ejemplo: `/blog/javascript/arrays`, `/blog/css/flexbox` , `/users/mau/posts/1`
#### Ventajas de las rutas dinámicas anidadas
* Son ideales cuando se tiene que representar relaciones (padre/hijo).
* Mejoran exponencialmente el contexto de la URL.
* Su mayor uso es en productos de tienda, comentarios dentro de un post.
* Permite acceder a múltiples parámetros (`params`).
#### ¿Cómo se crean?
Siguiendo la misma lógica de una ruta dinámica:
* Crear dentro de la carpeta `src/app` la estructura de carpetas correspondiente a la ruta deseada, definiendo entre `[foldername]` las carpetas necesarias que van a ser el parámetro dinámico.
* Dentro de esa carpeta o de las carpetas que queremos que sean rutas públicas, se debe crear un archivo llamado `page.tsx`.
* Exporta un componente de React por defecto.
* Accede a los parámetros dinámicos desde `params` en el componente de página.
#### ¿Cómo funcionan?
Next.js con App Router analiza la carpeta `/app` y genera automáticamente las rutas:
* Mapea todas las carpetas y subcarpetas que estén dentro de `/app`.
* Cada carpeta representa una parte del path en la URL.
* Si una carpeta tiene un nombre entre corchetes (`[param]`), se trata como un **segmento dinámico**.
* Solo considera una carpeta como parte de una ruta si co-localiza archivos especiales, el resto las ignora.
#### Ejemplo
src/app/blog/[category]/posts/[name]/page.tsx → /blog/javascript/posts/arrays
// src/app/blog/[category]/posts/[name]/page.tsx
interface PageParams {
category: string;
name: string;
}
// La propiedad params es asincrona, por lo que se debe de tratar como promesa
interface PageProps {
params: Promise<PageParams>;
}
export default async function BlogPostPage({ params }: PageProps) {
// Desestructuramos los parámetros de la promesa
const { category, name } = await params;
return (
<div className="p-4">
<h1 className="text-2xl font-bold">Post: {name}</h1>
<p className="text-lg">Categoría: {category}</p>
</div>
);
}
Al iniciar el servidor (`npm run dev`), podrás acceder a esta página visitando:
http://localhost:3000/blog/javascript/posts/arrays
src/app/blog/[category]/posts/[name]/page.tsx
→ /blog/javascript/posts/nodejs-introduction
→ { category: 'javascript', name: 'nodejs-introduction' }
src/app/blog/[category]/posts/[name]/page.tsx
→ /blog/css/posts/flexbox
→ { category: 'javascript', name: 'flexbox' }
> **Descarga el proyecto actual [ref] (branch: dynamic-routes)**
>
> **Recuerda** : que si intentas acceder a `/blog` o `/blog/[category]` o `/blog/[category]/posts` saldrá el mensaje: `404 | This page could not be found.`
Hasta este punto, ya sabes cómo **crear páginas en Next.js** , conoces las **rutas dinámicas** y **rutas dinámicas anidadas**.