Novedades de Astro 7.4: --timings, imágenes por entorno y prerenderizado en paralelo
Astro 7.4 te dice en qué se va el tiempo de tu build con astro build --timings, permite un servicio de imagen para el build y otro para runtime, añade notFound() y dos funciones experimentales. Además, el mínimo de Node.js subió dos veces en esta versión.
- Javi Mata
- 13 min de lectura
Tabla de contenido
- Qué trae Astro 7.4
- Cómo actualizar
- astro build --timings: dónde se va el tiempo de tu build
- Un servicio de imagen para el build y otro para runtime
- Si mantienes una integración o un prerenderer
- notFound() para entrypoints personalizados
- Avisos en la configuración de fuentes
- El mínimo de Node.js subió dos veces
- Experimental: prerenderizado en paralelo
- Experimental: página de redirección personalizada
- Otras mejoras
- Mi opinión
- Fuentes
Astro 7.4 se anunció el 15 de octubre de 2026. Si leíste el artículo de Astro 7.3, aquella era una versión pequeña para quien extiende Astro. Esta es más útil para el día a día: la novedad principal es un flag que te dice en qué se va el tiempo de tu build.
Todo lo que cuento sale del anuncio oficial, de la documentación de docs.astro.build y del changelog del paquete astro, consultados el 6 de noviembre de 2026. Los ejemplos de código son los del anuncio. A esa fecha, la versión más reciente en npm es la 7.4.7, publicada el 5 de noviembre de 2026.
Qué trae Astro 7.4
- El flag
--timingsenastro build, con un resumen de dónde se fue el tiempo. - Servicios de imagen separados para el build y para runtime.
- Un handler
notFound()para quien arma su propio entrypoint de servidor o worker. - Avisos cuando tu configuración de fuentes pide algo que el proveedor no tiene.
- Un nuevo mínimo de Node.js (que además cambió otra vez en un parche, ojo con esto).
- Dos funciones experimentales: prerenderizado en paralelo y página de redirección personalizada.
Cómo actualizar
El anuncio recomienda la herramienta automática:
npx @astrojs/upgrade
O, de forma manual, con el comando de tu gestor de paquetes:
npm install astro@latest
pnpm upgrade astro --latest
yarn upgrade astro --latest
Antes de hacerlo, revisa tu versión de Node.js: está explicado más abajo.
astro build --timings: dónde se va el tiempo de tu build
Cuando un build se vuelve lento, no siempre es obvio por qué: ¿un plugin de Vite, el resaltado de sintaxis, el procesamiento de imágenes o una página especialmente pesada? Ahora astro build acepta un flag nuevo:
astro build --timings
Al terminar el build, Astro imprime un resumen de dónde se fue el tiempo. Según la referencia del CLI, el reporte cubre las fases del build, los plugins de Vite, el procesamiento de Markdown y el resaltado de sintaxis, el renderizado de páginas, la optimización de imágenes y los hooks de las integraciones.
El anuncio lo muestra con un caso muy realista. Tomaron el blog starter de Astro y añadieron una sección de comentarios al layout de los artículos. Cada comentario pide, además, el perfil de quien lo escribió:
---
const { comment } = Astro.props;
// Look up the commenter's profile for every comment
const res = await fetch(`https://jsonplaceholder.typicode.com/users?email=${comment.email}`);
const [user] = await res.json();
---
<article>
<strong>{user?.name ?? comment.name}</strong>
<p>{comment.body}</p>
</article>
En el editor nada se ve mal. Pero las peticiones de perfiles no pueden empezar hasta que llegan los comentarios, así que cada página espera dos viajes de red seguidos. Esta es la salida de astro build --timings que publica el anuncio (recortada por ellos mismos):
build timings
total 2.61s · 9 pages · output "static"
Build phases
resolve config 59ms 2.3% ▄·····················
setup 225ms 8.6% ▃█▅···················
route discovery 2ms 0.1% ▁·····················
vite config 14ms 0.5% ▁·····················
content sync 206ms 7.9% ▂█▅···················
prerender bundle 151ms 5.8% ··▃█··················
client bundle 21ms 0.8% ····▂·················
manifest injection 2ms 0.1% ····▁·················
generate pages 2.10s 80.6% ····▇█████████████████
prerenderer setup 6ms 0.2% ····▁·················
static paths 3ms 0.1% ····▁·················
Page rendering (2.09s across 9 pages)
component render 2.08s 79.6% ····▆█████████████████
page pipeline 13ms 0.5%
Slowest pages (median 297ms · p95 571ms)
/about 571ms
/blog/first-post 307ms /blog/[...slug]
/blog/using-mdx 303ms /blog/[...slug]
/blog/second-post 299ms /blog/[...slug]
/blog/third-post 297ms /blog/[...slug]
/blog/markdown-style-guide 296ms /blog/[...slug]
/rss.xml 10ms
/blog 6ms
Se lee de arriba abajo:
- Generar páginas se lleva el 80.6% del build.
- Casi todo ese tiempo está en el renderizado de componentes (
component render), no en el pipeline de Astro. - Las páginas lentas son las que usan el layout de artículo;
/blogy/rss.xmltardan milisegundos.
Eso apunta directo a algo que renderiza el layout. En el anuncio, pedir los comentarios y todos los perfiles a la vez con Promise.all() y pasar cada perfil al componente bajó la generación de páginas de 2.10 s a 1.13 s, y redujo a la mitad el tiempo de cada artículo.
El anuncio lo plantea como el primer paso antes de probar otras optimizaciones, como el prerenderizado en paralelo o los builds incrementales, para saber qué parte del build atacar. Estoy de acuerdo: medir antes de optimizar te ahorra cambios a ciegas.
Un servicio de imagen para el build y otro para runtime
Las páginas prerenderizadas y las que se renderizan bajo demanda tienen necesidades distintas con las imágenes:
- En el build hay tiempo de sobra y un entorno completo de Node.js, así que un optimizador local como Sharp funciona bien.
- Bajo demanda, el código corre en tu servidor o en el edge, muchas veces en un runtime donde Sharp no puede ejecutarse. Ahí suele convenir un CDN de imágenes.
Hasta ahora había que elegir un solo servicio para los dos casos, o dejar que el adaptador decidiera. En Astro 7.4, image.service también acepta un servicio build y uno runtime:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
image: {
service: {
build: { entrypoint: 'astro/assets/services/sharp' },
runtime: { entrypoint: 'my-image-cdn-service' },
},
},
});
my-image-cdn-service es el nombre de ejemplo que usa el anuncio; ahí iría el servicio de tu CDN. Según la referencia de configuración:
- El servicio
buildoptimiza las imágenes de las páginas prerenderizadas durante el build y también se usa en desarrollo. - El servicio
runtimeatiende las imágenes de las páginas bajo demanda y el endpoint de imágenes del sitio desplegado.
Si pasas un solo servicio, como antes, todo sigue funcionando igual.
Si mantienes una integración o un prerenderer
Este cambio tiene letra pequeña para autores de integraciones. config.image.service conserva la forma que configuró el usuario. Si el proyecto define build y runtime, entonces config.image.service.entrypoint y config.image.service.config son undefined, así que hay que comprobar si existe runtime:
'astro:config:done': ({ config }) => {
const { service } = config.image;
const runtimeService = 'runtime' in service ? service.runtime : service;
// ...
},
Además, los prerenderers personalizados ahora informan de las imágenes de cada página a través de los metadatos que devuelven getStaticPaths() y render(). Si envuelves el prerenderer por defecto con setPrerenderer(), tienes que pasar esos metadatos:
setPrerenderer((defaultPrerenderer) => ({
name: 'my-prerenderer',
async getStaticPaths() {
const result = await defaultPrerenderer.getStaticPaths();
const { paths, metadata } = Array.isArray(result) ? { paths: result } : result;
return { paths: paths.filter(({ pathname }) => !pathname.startsWith('/drafts')), metadata };
},
render(request, options) {
return defaultPrerenderer.render(request, options);
},
}));
Devolver un array simple desde getStaticPaths() o un Response simple desde render() sigue funcionando, pero está obsoleto, y las imágenes de esas páginas no se generarán.
Si usas Cloudflare o Markdoc, el anuncio pide actualizar @astrojs/cloudflare y @astrojs/markdoc junto con astro, porque sus nuevas versiones requieren astro@^7.4.0. Con este cambio, @astrojs/cloudflare procesa las imágenes de las páginas prerenderizadas con el mismo pipeline que el resto de adaptadores.
notFound() para entrypoints personalizados
Los handlers componibles de astro/fetch y astro/hono te dejan armar tu propio entrypoint de servidor o de worker con las piezas de Astro. El problema: si usabas pages() sin el handler todo-en-uno astro(), una petición que no coincidía con ninguna ruta devolvía un 404 vacío en lugar de tu página 404.astro, aunque estuviera prerenderizada.
Astro 7.4 añade notFound(). Va antes de pages():
// src/worker.ts
import { Hono } from 'hono';
import { notFound, pages } from 'astro/hono';
import { cf } from '@astrojs/cloudflare/hono';
const app = new Hono();
app.use(cf());
app.use(notFound());
app.use(pages());
export default app;
El mismo handler existe en astro/fetch. Según la referencia de notFound(), devuelve undefined si la ruta sí coincide (y entonces sigues procesando), y en un pipeline con astro/fetch va antes de middleware() y pages(). Si usas astro(), no tienes que hacer nada: ya incluye este comportamiento.
Avisos en la configuración de fuentes
Es fácil pedir un peso o un subset que una familia tipográfica no ofrece, y hasta ahora te enterabas cuando el texto se veía mal. Los proveedores de fuentes pueden implementar un callback opcional, getFontProperties(), que informa de los pesos, estilos, subsets y formatos que la familia tiene de verdad. Con eso, Astro te avisa de cada valor de tu configuración que el proveedor no puede servir.
Todos los proveedores integrados de Astro ya lo implementan, así que si usas uno de ellos no tienes que hacer nada. Si mantienes un proveedor propio, este es el ejemplo del anuncio:
import type { FontProvider } from 'astro';
const provider: FontProvider = {
name: 'my-provider',
resolveFont: ({ familyName }) => {
// ...
},
getFontProperties: ({ familyName }) => ({
weights: ['400', '700'],
styles: ['normal', 'italic'],
subsets: ['latin'],
formats: ['woff2'],
}),
};
Es opcional en Astro 7, pero será obligatorio en Astro 8, así que conviene añadirlo ya. Según la referencia de proveedores de fuentes, si la familia no la conoce tu proveedor, devuelve undefined y Astro se salta la comprobación. Además, el contexto de init() de los proveedores incluye ahora una función fetch() que reintenta los fallos transitorios.
El mínimo de Node.js subió dos veces
Este es el punto en el que más conviene fijarse, porque el anuncio ya no cuenta toda la historia:
- Astro 7.4.0 (15 de octubre) subió el mínimo a Node.js 22.22.0, la última versión de Node 22 que soporta StackBlitz, según el anuncio.
- Astro 7.4.2 (21 de octubre) lo volvió a subir, en un parche, a Node.js 22.23.4. El changelog explica que esa versión incluye las correcciones de las actualizaciones de seguridad de Node.js de octubre de 2026, y que la política de soporte de Node.js de Astro permite subir el mínimo en un parche cuando un fallo de seguridad de Node.js afecta a Astro.
- Astro 7.4.3 hace una excepción: deja correr el CLI con Node.js
>=22.22.0dentro de WebContainers (StackBlitz), donde el usuario no puede cambiar la versión de Node.
Hoy, los requisitos de instalación dicen: Node.js v22.23.4 o superior, y las versiones impares como la v23 no están soportadas. Puedes comprobar la tuya con:
node -v
Un caso real: en el equipo donde escribo este blog tengo Node v22.23.3, justo por debajo del mínimo. Si tú también estás en una 22.x anterior a la 22.23.4, actualiza Node.js antes de actualizar Astro. Y revisa también la versión de Node que usa tu servicio de despliegue y tu CI.
Experimental: prerenderizado en paralelo
Astro ya renderizaba las páginas estáticas de forma concurrente, pero en un solo hilo. En sitios grandes con páginas que consumen mucha CPU, el build se quedaba en un núcleo aunque tu máquina tuviera más.
El flag experimental.parallelPrerender renderiza las páginas estáticas en worker threads de Node.js:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
parallelPrerender: true,
},
});
Por defecto usa todos los núcleos disponibles menos uno. Cada worker suma memoria al build, así que si te quedas sin memoria o el build no se acelera, baja el número con workers:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
parallelPrerender: {
workers: 4,
},
},
});
Cada worker renderiza tantas páginas a la vez como permita tu ajuste build.concurrency.
La documentación de la función añade limitaciones que el anuncio no detalla:
- Las páginas renderizadas en paralelo no comparten variables a nivel de módulo. Un valor que guardas en caché en una variable al renderizar una página puede no estar disponible al renderizar otra.
- No se pueden renderizar en paralelo las páginas cuyas props de
getStaticPaths()contengan valores no serializables, como funciones o instancias de clases. - El flag no tiene efecto si tu adaptador trae su propia forma de prerenderizar. Entre los adaptadores oficiales, eso solo aplica a
@astrojs/cloudflare, y Astro muestra un aviso durante el build.
El primer punto me parece el más traicionero: si tienes un “cache casero” en una variable del módulo para no repetir peticiones entre páginas, con este flag puede dejar de servirte. Según el anuncio, combina bien con los builds estáticos incrementales de Astro 7.2: los incrementales se saltan las páginas que no cambiaron y el paralelo reparte las que sí entre los núcleos.
Experimental: página de redirección personalizada
Un sitio estático no tiene servidor que envíe la cabecera HTTP Location. Por eso, para cada redirección que genera, Astro crea una pequeña página HTML con una etiqueta <meta http-equiv="refresh">. Eso incluye las redirecciones de la configuración redirects, las llamadas a Astro.redirect() en páginas prerenderizadas y las redirecciones de i18n. El problema: el marcado, el texto y el retraso de esa página eran fijos, así que no podías traducirla ni darle tu marca.
El flag experimental.redirectPage te deja poner la tuya:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
redirectPage: true,
},
});
Después creas src/pages/3xx.astro. Astro la renderiza una vez por cada redirección y le pasa from, to, status y delay como props:
---
// src/pages/3xx.astro
import type { RedirectPageProps as Props } from 'astro';
const { from, to, status, delay } = Astro.props;
---
<html lang="en">
<head>
<meta http-equiv="refresh" content={`${delay};url=${to}`} />
<meta name="robots" content="noindex" />
<title>Redirecting…</title>
</head>
<body>
<p>This page has moved. <a href={to}>Continue to {to}</a>.</p>
</body>
</html>
Para un blog en español, lo natural sería cambiar lang="en" y los textos; eso ya es adaptación mía, no parte del ejemplo oficial.
Puntos importantes, según el anuncio y la documentación de la función:
- En un build estático, la etiqueta
<meta http-equiv="refresh">es la redirección. Tu página tiene que incluirla apuntando ato; si falta o apunta a otro destino, Astro avisa durante el build. - Si tu página falla al renderizar o no existe, Astro usa su página integrada.
delayes el retraso en segundos: Astro usa2para las redirecciones 302 y0para los demás códigos.- Astro también genera
3xx.astrocomo una ruta normal,/3xx, escrita en3xx.html. Si alguien la visita directamente, no recibe props de redirección. - Las redirecciones de páginas bajo demanda no cambian: siguen usando la cabecera
Location.
Otras mejoras
El anuncio menciona además que las integraciones y los plugins de Vite ahora pueden controlar dónde se escribe la salida del build (cliente, servidor y prerender), y que los prerenderers personalizados pueden leer esas rutas finales desde un nuevo contexto outputDirectories en setPrerenderer(). Para la lista completa de correcciones, consulta el changelog oficial.
Mi opinión
Esto es opinión mía, no del anuncio. Si solo vas a probar una cosa de esta versión, que sea astro build --timings: no cambia nada de tu proyecto y te dice dónde está el problema antes de tocar código. El ejemplo de los comentarios es muy común: componentes que hacen fetch en cascada sin que nadie lo note.
El prerenderizado en paralelo vale la pena en sitios con muchas páginas, pero por ser experimental y por la limitación de las variables de módulo, yo lo probaría primero en una rama y compararía tiempos con --timings.
Y antes de nada, revisa Node.js. Para que quede claro: este blog todavía está en Astro 5, así que para mí pasar a la 7.4 sería un salto de versión mayor, no una actualización de rutina.
Fuentes
- Astro 7.4 (anuncio oficial, 15 de octubre de 2026)
- Changelog del paquete
astro - Referencia del CLI:
--timings - Referencia de configuración:
image.service - Referencia de integraciones:
setPrerenderer() - Referencia de
astro/fetch:notFound() - Referencia de proveedores de fuentes:
getFontProperties() - Requisitos de instalación de Astro
- Política de soporte de Node.js en Astro
- Actualizaciones de seguridad de Node.js de octubre de 2026
- Prerenderizado en paralelo (experimental)
- Página de redirección personalizada (experimental)
- Astro 7.2: builds estáticos incrementales
- Versiones de
astroen npm
Etiquetas:
Compartir: