wandres.dev
RUTAS DINÁMICAS · params y getStaticPaths

Rutas dinámicas con [param]

El salto de un fichero una URL a un fichero una familia de URLs: los corchetes en el nombre del archivo convierten un segmento en un parámetro, y Astro.params entrega su valor. Por qué el nombre entre corchetes es a la vez patrón y variable, y por qué un patrón obliga a repensar la correspondencia entre estructura y ruta.

⏱ 14 min

Hasta aquí cada fichero de src/pages valía por una URL exacta: about.astro servía /about y nada más. Las rutas dinámicas rompen esa correspondencia uno a uno. Al envolver el nombre del fichero entre corchetes —[slug].astro— dejas de nombrar una dirección y pasas a describir un patrón de direcciones: una plantilla que casa con cualquier valor que ocupe ese segmento. Un solo fichero se convierte así en la fuente de una familia entera de páginas, y Astro.params es la ventana por la que ese fichero descubre con qué valor concreto lo han invocado.

🎯 Al terminar esta lección sabrás
  • Declarar un segmento dinámico envolviendo el nombre del fichero entre corchetes.
  • Distinguir un fichero como URL única de un fichero como patrón de URLs.
  • Leer el valor del segmento con Astro.params y su clave homónima.
  • Entender que un parámetro es siempre una cadena y por qué eso importa.

El corchete convierte un nombre en una variable

En el enrutado por ficheros, el nombre del archivo es el segmento de la URL. Las rutas dinámicas explotan esa equivalencia con un gesto mínimo: rodear el nombre de corchetes para que deje de leerse como literal y pase a leerse como hueco. src/pages/blog/post.astro casa exactamente con /blog/post; src/pages/blog/[slug].astro casa con /blog/lo-que-sea —con cualquier valor en ese tramo—.

La palabra que escribes dentro de los corchetes no es mágica ni reservada: es un nombre que tú eliges para el parámetro. [slug], [id], [producto] funcionan igual; solo cambia la etiqueta con la que después recuperarás el valor. Elegir un nombre descriptivo es documentar, en el propio fichero, qué representa ese segmento.

src/pages/
├─ blog/
│  ├─ post.astro       ->  /blog/post        (literal, una URL)
│  └─ [slug].astro     ->  /blog/cualquiera  (patron, muchas URL)
└─ productos/
   └─ [id].astro       ->  /productos/42, /productos/abc, ...

El cambio conceptual es profundo. Un fichero literal responde a la pregunta qué URL sirvo; un fichero con corchetes responde a qué forma tienen las URLs que sirvo. Pasas de enumerar direcciones a describir su gramática. Y esa gramática puede combinar tramos fijos con tramos variables: src/pages/tienda/[categoria]/[id].astro casa con /tienda/ropa/17, con dos parámetros —categoria e id— extraídos de una misma URL.

El orden y la mezcla son libres. Puedes anteponer segmentos literales a los variables, intercalarlos o encadenar varios huecos seguidos —blog/[year]/[slug].astro casa con /blog/2026/mi-post—. Astro respeta los tramos literales como anclas y solo trata como variable lo que envuelves en corchetes. El fichero deja de ser un punto en el mapa de rutas para volverse una plantilla con ranuras, tantas como corchetes contenga.

ℹ️
El nombre del corchete es tuyo, la clave lo hereda

Lo único que fija el framework es la correspondencia: el texto que pongas entre corchetes será, letra por letra, la clave con la que leas el valor. Si el fichero es [slug].astro, el valor vive en Astro.params.slug; si es [id].astro, en Astro.params.id. No hay traducción ni convención oculta: el nombre del hueco y el nombre de la variable son el mismo, y por eso conviene que ese nombre diga la verdad sobre lo que captura.

Astro.params: la ventana al valor concreto

Declarar el patrón es la mitad; leer el valor con el que se ha activado es la otra. Dentro del frontmatter, Astro.params es un objeto cuyas claves son exactamente los nombres de los corchetes de ese fichero. Para [slug].astro, Astro.params.slug te devuelve el tramo que el visitante puso en esa posición de la URL.

---
// src/pages/blog/[slug].astro
const { slug } = Astro.params;
---
<h1>Estas leyendo el post: {slug}</h1>

Si alguien visita /blog/hola-mundo, ese mismo fichero se ejecuta con slug igual a hola-mundo. La página no sabe —ni necesita saber— cuántas variantes de sí misma existen: solo recibe el valor de su turno y construye la respuesta a partir de él. Es la inversión exacta del modelo estático: en vez de un fichero por página, un fichero que se reencarna en tantas páginas como valores reciba.

Un detalle que ahorra horas de depuración: el valor de un parámetro es siempre una cadena. La URL es texto, y Astro no adivina tipos por ti. Si tu [id] representa un número, Astro.params.id te llega como "42", no como 42; compararlo con un entero o usarlo como índice sin convertirlo antes es una fuente clásica de fallos silenciosos. La conversión —Number(id), un parseInt— es responsabilidad tuya, y hacerla explícita deja claro dónde cruzas la frontera entre el texto de la URL y el dato tipado de tu lógica.

Algunas consecuencias de que todo parámetro sea texto conviene tenerlas presentes:

  • Comparar con un número —id === 42— siempre falla; compara con la cadena '42' o convierte antes.
  • Los ceros a la izquierda sobreviven: 007 no es 7, lo que a veces ayuda y a veces sorprende.
  • Como índice de un array hay que convertirlo; como clave de un objeto, se usa tal cual.

Cuando un fichero declara varios segmentos dinámicos, Astro.params los reúne todos en un mismo objeto: una clave por cada corchete, poblada en la misma petición. Desestructurarlo es la forma natural de leerlos juntos.

---
// src/pages/tienda/[categoria]/[id].astro
const { categoria, id } = Astro.params;
---
<p>Categoria {categoria} y producto {id}</p>

Una sola URL, /tienda/ropa/17, produce dos parámetros a la vez —categoria igual a ropa, id igual a 17— y ambos llegan por ese mismo objeto. El número de claves de Astro.params es exactamente el número de corchetes del fichero: la lectura nunca inventa ni pierde parámetros.

flowchart LR
F[archivo blog slug punto astro] --> P{patron de ruta}
P --> U1[blog hola]
P --> U2[blog adios]
P --> U3[blog otro]
U1 --> A[Astro params slug igual hola]
U2 --> B[Astro params slug igual adios]
U3 --> C[Astro params slug igual otro]
style F fill:#89b4fa,color:#11111b
style A fill:#a6e3a1,color:#11111b
style B fill:#a6e3a1,color:#11111b
style C fill:#a6e3a1,color:#11111b

Conviene fijar el vocabulario, porque se confunde a menudo. El segmento dinámico es el hueco en el patrón —[slug], tal como aparece en el nombre del fichero—. El parámetro es la pareja nombre-valor que resulta de casar una URL concreta con ese patrón —slug igual a hola-mundo—. El fichero declara segmentos; cada petición produce parámetros. Uno es la plantilla, el otro es la instancia.

💡
Nombra el parámetro por lo que representa

Como el nombre del corchete es a la vez la clave de Astro.params y la documentación del fichero, elígelo con criterio. [id] anuncia un identificador opaco; [slug], un fragmento legible derivado de un título; [categoria], un valor de un conjunto acotado. La palabra no altera el comportamiento —cualquiera funciona— pero sí la legibilidad: quien abra src/pages/tienda/[categoria]/[producto].astro intuye la forma de esas URLs sin leer una línea de lógica. Un buen nombre de parámetro es la primera documentación de la ruta.

Un patrón describe infinitos casos; el build necesita finitos

Aquí aparece la tensión que gobierna todo este nivel. Un patrón como [slug] describe, en teoría, infinitas URLs: /blog/a, /blog/b, /blog/lo-que-se-te-ocurra. Pero un sitio estático se compila a ficheros HTML antes de que nadie lo visite, y no puede generar infinitos ficheros para infinitos valores imaginables. Alguien tiene que decirle a Astro cuáles de esos infinitos casos existen de verdad.

Esa es la razón de ser de getStaticPaths, la función que veremos en la próxima lección: en modo estático, un fichero con corchetes está obligado a exportarla para enumerar los valores concretos que quiere materializar. Sin ella, Astro no sabe qué páginas hornear y la compilación falla con un error explícito. El patrón describe la gramática; getStaticPaths selecciona las frases de esa gramática que de verdad se pronuncian.

Conviene ver esta obligación como coherencia, no como capricho. Un sitio estático no tiene un proceso vivo que, ante una URL nueva, salga a averiguar si le corresponde una página; todo lo que existe se decidió y se escribió en disco durante el build. Pedirle que sirva un valor que nadie enumeró sería pedirle que consulte a un servidor que no está. Enumerar no es burocracia: es la única forma de que un artefacto sin ejecución en tiempo real sepa qué contiene.

🎯

Un fichero, muchas URL

Los corchetes convierten un fichero en un patron que casa con un segmento variable. Una plantilla, una familia entera de paginas.

🔑

La clave hereda el nombre

El texto entre corchetes es la clave de Astro.params. Si el fichero es id, el valor vive en Astro.params.id.

🧵

Siempre una cadena

Todo parametro llega como texto. Convertirlo a numero o a otro tipo es trabajo tuyo, y conviene hacerlo explicito.

🧭

El patron no basta

En estatico, describir la forma de las URL no dice cuales existen. Enumerarlas es tarea de getStaticPaths.

Este modo estático no es el único: en renderizado bajo demanda no hay que enumerar nada, porque el servidor resuelve el parámetro en el momento de cada petición. Pero esa flexibilidad tiene su propio precio y su propia lección al final del nivel. Por ahora, retén la idea vertebral: los corchetes describen qué forma pueden tener las rutas, y decidir cuáles de esas rutas existen es una segunda pregunta, con respuestas distintas según el modo de renderizado.

⚠️
Un fichero dinámico solo no compila en estático

Si creas [slug].astro en un sitio estático y no exportas getStaticPaths, el build no se queda callado: falla pidiéndote precisamente esa función. Es un error deseable, no un estorbo. Astro se niega a adivinar qué páginas quieres y prefiere que las declares. Cuando lo veas, no es un bug: es la señal de que has descrito un patrón sin decir todavía qué casos concretos debe materializar.

Nombrar un patrón es cambiar la pregunta que le haces al sistema de ficheros

El corchete parece un truco de sintaxis —dos caracteres alrededor de un nombre— pero encierra un salto de nivel de abstracción que reaparece por toda la informática. Un fichero literal es un valor: representa una URL concreta y solo esa. Un fichero con corchetes es una función: representa una regla que, alimentada con un valor, produce una página. Has pasado de enumerar a describir, de la extensión a la intensión, de la lista al patrón. Es exactamente el mismo salto que separa escribir cien líneas casi iguales de escribir un bucle que las genera, o listar los pares ordenados de una relación frente a dar la ecuación que los produce. Y como toda subida de abstracción, este salto compra poder y cobra un impuesto. El poder es evidente: mil artículos de blog dejan de ser mil ficheros para ser un fichero y mil datos. El impuesto es más sutil: cuando el fichero es un patrón, ya no puedes leer del árbol de src/pages qué URLs existen —el árbol te dice la forma de las rutas, no su contenido—. Esa información se ha mudado del sistema de ficheros a los datos, y por eso hace falta una segunda pieza, getStaticPaths o el servidor, que reconecte el patrón con el mundo real de valores que debe cubrir. Interiorizar rutas dinámicas no es memorizar una sintaxis: es aceptar que has movido la fuente de verdad de dónde vive un fichero a qué dice un dato, y organizar el resto de tu razonamiento alrededor de esa mudanza.

⚔️ Tu primer patrón de rutas
  1. Crea src/pages/blog/[slug].astro y muestra en un <h1> el valor de Astro.params.slug; observa que un solo fichero describe muchas URLs.
  2. Visita /blog/hola y /blog/adios y comprueba que la misma plantilla se reencarna con parámetros distintos.
  3. Crea src/pages/tienda/[categoria]/[id].astro y pinta ambos parámetros; razona cómo una URL produce dos valores.
  4. Haz Number(Astro.params.id) y comprueba que sin la conversión el parámetro era una cadena; anota por qué eso importa.