Rewrites con Astro.rewrite()
Una operación emparentada con la redirección pero de naturaleza opuesta: la reescritura sirve el contenido de otra ruta sin mover la barra de direcciones. Una sola petición, la misma URL visible, contenido distinto por dentro. Cómo se invoca Astro.rewrite, qué acepta como destino, por qué solo existe bajo demanda y en qué se diferencia, punto por punto, de un redirect.
Astro.rewrite: servir otro contenido sin mover la URL
Astro.rewrite toma un destino y renderiza el contenido de esa ruta como respuesta a la petición actual, sin tocar la barra de direcciones. Es una operación interna del servidor: el visitante nunca se entera de que lo que ve vive, en el árbol de ficheros, en otro sitio.
---// src/pages/[handle].astroexport const prerender = false;const usuario = await buscarUsuario(Astro.params.handle);if (!usuario) { return Astro.rewrite('/404');}---<h1>{usuario.nombre}</h1>Ese Astro.rewrite('/404') hace que, cuando el handle no corresponde a nadie, el servidor renderice el contenido de tu src/pages/404.astro —con su layout, sus estilos, su buscador— pero lo entregue bajo la URL que el visitante pidió. No hay salto, no hay parpadeo, no hay una segunda petición: la dirección sigue siendo la del perfil inexistente y, sin embargo, lo que se pinta es tu página de error cuidada. Como con Astro.redirect, la llamada construye una respuesta que debes retornar; olvidarlo deja seguir el render y romper al leer datos de un usuario nulo.
La potencia del gesto está en que desacopla dos cosas que solemos confundir: la URL, que es la identidad pública de la petición, y el componente que la atiende, que es un detalle interno. Con una reescritura puedes cambiar el segundo sin tocar el primero, y esa libertad es la que da a la reescritura sus usos más interesantes, todos variaciones de una misma idea: mismo nombre público, distinta implementación por dentro.
Reescribir no es redirigir: una petición frente a dos
La confusión entre rewrite y redirect es tan común que merece desmontarse paso a paso, porque eligen mal quienes no ven la diferencia. Ambas mandan al visitante a otro contenido, pero el camino es distinto y las consecuencias también.
Una redirección es una conversación de dos turnos. El servidor responde a la primera petición con un código 30x y una cabecera Location; el navegador lee esa cabecera, actualiza su barra de direcciones y emite una segunda petición a la nueva URL; solo entonces recibe el contenido. El visitante ve cómo la dirección cambia, y hay dos viajes por la red.
Una reescritura es un solo turno. El servidor recibe la petición, decide por dentro renderizar otra ruta, y devuelve ese contenido en la misma respuesta. El navegador no sabe que hubo un cambio de ruta interno: pidió una URL, recibió contenido, y la barra de direcciones no se movió. Un viaje, una URL, contenido de otra parte.
Hay también una diferencia de coste que a veces inclina la balanza. La redirección paga un viaje de red extra: la respuesta 30x viaja, el navegador la interpreta y vuelve a pedir. La reescritura resuelve todo en el servidor dentro de la misma petición, sin ese ida y vuelta. Para una página de error o una variante servida al vuelo, evitar el segundo viaje se nota, sobre todo en conexiones lentas.
Dónde vive, qué acepta y las formas de invocarla
Como toda operación que decide en el momento de la petición, Astro.rewrite solo tiene sentido en renderizado bajo demanda: necesita un servidor vivo que reciba la URL, tome la decisión y renderice otra ruta al vuelo. En un sitio puramente estático no hay tal momento —todo se horneó en el build—, así que la reescritura no es una herramienta disponible allí. Es, por naturaleza, un mecanismo de servidor.
El destino admite varias formas, y conviene conocerlas. La más habitual es una ruta como cadena —Astro.rewrite('/404')—. Pero también acepta una instancia de URL, útil cuando la compones a partir de datos, y una Request completa, para casos avanzados donde quieres controlar cabeceras o método de la petición reescrita. Sea cual sea la forma, Astro vuelve a entrar en su fase de enrutado con ese destino: localiza la ruta que casa, ejecuta de nuevo el middleware y renderiza el componente correspondiente.
---export const prerender = false;// segun una bandera, servir la variante sin cambiar la URLconst variante = Astro.cookies.get('experimento')?.value;if (variante === 'b') { return Astro.rewrite('/landing-b');}---<h1>Landing A</h1>Los usos naturales de la reescritura son todos variaciones de mismo nombre, distinta implementación:
- Servir una página de error con su maqueta completa bajo la URL que falló, sin desviar al visitante.
- Atender un idioma distinto reescribiendo hacia la variante localizada según la cabecera o una cookie.
- Mostrar una página de mantenimiento para una sección entera sin cambiar sus direcciones.
- Repartir tráfico entre variantes en un experimento A/B manteniendo una sola URL pública.
- Servir contenido heredado desde una ruta nueva sin romper los enlaces antiguos.
La reescritura también vive en el middleware, donde encaja de forma natural. La función next que recibe el middleware acepta, además de su uso normal, una ruta a la que reescribir: llamar a next('/otra-ruta') reencamina la petición hacia ese destino antes de renderizar. Colocada ahí, una reescritura se vuelve una política transversal —internacionalización, mantenimiento, banderas de funcionalidad— que se aplica a familias enteras de rutas sin tocar cada página.
// src/middleware.tsimport { defineMiddleware } from 'astro:middleware';export const onRequest = defineMiddleware((context, next) => { if (enMantenimiento && !context.url.pathname.startsWith('/admin')) { return next('/mantenimiento'); } return next();});Aquí next('/mantenimiento') reescribe toda petición que no sea del panel hacia la página de mantenimiento, sin cambiar la URL y desde un solo punto del código. Una llamada a next sin argumento sigue el flujo normal; con una ruta, reescribe. Esa capacidad de reencaminar desde el middleware es lo que convierte la reescritura en una política de sitio, y no en un parche repetido página por página.
El estado de la respuesta y el SEO
Una duda frecuente es qué código de estado sale cuando reescribes. La respuesta es limpia: la respuesta lleva el estado que produzca la ruta renderizada, no la pedida. Si reescribes hacia una página normal, sale un 200, porque esa página se renderiza con normalidad; si reescribes hacia tu ruta de error /404, Astro la trata como la página de error que es y emite el estado que corresponde. Por eso reescribir a /404 es el patrón idóneo para un recurso ausente: el visitante conserva su URL, ve tu maqueta de error completa y el cliente recibe el 404 honesto que esperaba.
Ese desacople entre URL pedida y contenido servido tiene una cara delicada en el SEO, y conviene mirarla de frente. Mientras la reescritura sea hacia dentro —servir un error, atender un idioma, mostrar una variante— no hay problema: la URL pública sigue siendo única y significativa. El riesgo aparece si usas reescrituras para que varias URLs distintas muestren, en silencio, exactamente el mismo contenido: los buscadores lo verán como duplicado y no sabrán cuál indexar. Si dos direcciones deben mostrar lo mismo, decláralo con una etiqueta canónica o resuélvelo con una redirección; no lo escondas tras un espejo opaco.