🚀 Astro 7.4 — Build Timings, Image Services y Prerender Paralelo
La release que hace visible el build
Astro 7.4 salió el 15 de octubre de 2026 (autor: Matthew Phillips). La estrella es
--timings, un flag deastro buildque muestra exactamente dónde se va el tiempo. Además: servicios de imagen distintos para páginas prerenderizadas y on-demand,notFound()para entrypoints personalizados, avisos de configuración de fuentes, Node.js mínimo 22.22.0 y dos features experimentales.
- 🌐 Anuncio: astro.build/blog/astro-740
- 📦 Upgrade:
npx @astrojs/upgrade- 🧪 Experimentales:
parallelPrerender·redirectPage
⬆️ Actualizar
# Recomendado
npx @astrojs/upgrade
# Manual
npm install astro@latest
# o
pnpm upgrade astro --latest
# o
yarn upgrade astro --latestNode.js primero
El mínimo soportado para Astro y sus integraciones oficiales ahora es Node.js 22.22.0. Si estás en una 22 anterior, actualiza Node antes que Astro.
⏱️ Build timings (--timings)
Cuando un build se vuelve lento, no siempre es obvio qué lo causa: ¿un plugin de Vite, syntax highlighting, procesamiento de imágenes o una página pesada?
astro build --timingsAl terminar, Astro imprime un resumen de:
- Fases del build
- Plugins de Vite
- Procesamiento de Markdown y syntax highlighting
- Renderizado de páginas
- Imágenes
- Integraciones
Ejemplo real del anuncio
Un blog starter con un componente <CommentSection> que hace fetch de comentarios y luego, por cada comentario, fetch del perfil del autor:
total 2.61s · 9 pages · output "static"
generate pages 2.10s 80.6%
component render 2.08s 79.6%
page pipeline 13ms 0.5%
Slowest pages (median 297ms · p95 571ms)
/about 571ms
/blog/first-post 307ms
/blog/using-mdx 303ms
...Diagnóstico: el 81% del build se va en generar páginas, y casi todo dentro de componentes, no en el pipeline de Astro. Las páginas lentas son las que usan el layout del post.
Fix: hacer los fetches de comentarios y perfiles en paralelo con Promise.all() y pasar cada perfil a <Comment>. Resultado: de 2.10s a 1.13s en generación, y la mitad de tiempo por post.
Úsalo antes de optimizar a ciegas
--timingses el primer paso antes de probarparallelPrerendero builds incrementales: te dice qué parte atacar. También cubre plugins de Vite, archivos lentos de bundlear, plugins de Markdown, highlighting e imágenes.
🖼️ Servicios de imagen separados (build vs runtime)
Las páginas prerenderizadas y las on-demand tienen necesidades distintas:
| Momento | Entorno | Servicio ideal |
|---|---|---|
| Build | Node.js completo, sin prisa | Optimizador local como Sharp |
| Runtime | Server/edge, a veces sin Sharp | Image CDN |
Antes había que elegir uno para ambos o dejar que el adapter decidiera. Ahora image.service acepta build y 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' },
},
},
});build— imágenes de páginas prerenderizadas, generadas durante el build. También se usa en desarrollo.runtime— páginas on-demand y el endpoint de imágenes en producción.- Un solo servicio sigue funcionando igual que antes.
Para autores de integraciones
config.image.serviceconserva la forma configurada.- Si el proyecto define
buildyruntime,config.image.service.entrypointy.configsonundefined. Hay que comprobar la propiedadruntime:
'astro:config:done': ({ config }) => {
const { service } = config.image;
const runtimeService = 'runtime' in service ? service.runtime : service;
// ...
},- Los prerenderers personalizados deben reportar las imágenes de cada página en la metadata que devuelven
getStaticPaths()yrender(). - Devolver un array plano desde
getStaticPaths()o unResponseplano desderender()sigue funcionando pero está deprecado, y las imágenes de esas páginas no se generan. - Actualizar
@astrojs/cloudflarey@astrojs/markdocjunto conastro, porque sus nuevas versiones requierenastro@^7.4.0.
Cambio de pipeline
Astro reworked cómo rastrea las imágenes del build: los prerenderers ahora participan del pipeline propio de Astro.
@astrojs/cloudflareprocesa imágenes de páginas prerenderizadas con el mismo pipeline que el resto de adapters.
🧭 notFound() para entrypoints personalizados
Los handlers composables de astro/fetch y astro/hono permiten armar tu propio server/worker. Si usabas pages() sin el handler todo-en-uno astro(), una ruta inexistente devolvía un 404 vacío en vez de tu 404.astro, incluso si estaba prerenderizada.
Astro 7.4 agrega notFound(). Debe ir 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. astro() ya incluye este comportamiento, así que solo necesitas notFound() si compones los handlers a mano.
🔤 Avisos de configuración de fuentes
Es fácil pedir un peso o subset que la familia no ofrece, y antes solo lo descubrías cuando el texto se veía mal.
Los font providers ahora pueden implementar getFontProperties(), un callback opcional que reporta:
- Pesos (
weights) - Estilos (
styles) - Subsets
- Formatos
Astro avisa si tu configuración pide algo que el provider no puede servir. Todos los providers integrados lo soportan.
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'],
}),
};Obligatorio en Astro 8
getFontProperties()es opcional en Astro 7, pero será requerido en Astro 8. Si mantienes un provider custom, conviene implementarlo ya.El contexto de
init()también gana unfetch()que reintenta fallos transitorios; los providers que envuelven un provider de unifont pueden pasarlo tal cual.
⚙️ Experimental: prerender paralelo
Astro renderiza páginas estáticas concurrentemente, pero hasta ahora todo ocurría en un solo hilo. En sitios grandes con páginas costosas de CPU, el build quedaba limitado a un core.
// astro.config.mjs
export default defineConfig({
experimental: {
parallelPrerender: true,
},
});- Por defecto usa todos los cores disponibles menos uno.
- Cada worker aumenta la memoria del build. Si hay OOM o no mejora, bajar el número:
experimental: {
parallelPrerender: {
workers: 4,
},
},- Cada worker renderiza tantas páginas a la vez como permita
build.concurrency. - No tiene efecto cuando el adapter provee su propio prerendering. Entre los oficiales, solo
@astrojs/cloudflare; Astro avisa durante el build cuando se ignora. - Se combina bien con incremental static builds: los incrementales saltan páginas sin cambios y el paralelo reparte las que sí hay que renderizar.
🔀 Experimental: página de redirect personalizada
Un sitio estático no tiene servidor para mandar un header Location, así que Astro genera una página HTML con <meta http-equiv="refresh"> por cada redirect: config redirects, Astro.redirect() en páginas prerenderizadas y redirects de i18n.
Antes el markup, texto y delay eran fijos. Ahora:
experimental: {
redirectPage: true,
},Crear src/pages/3xx.astro. Astro lo renderiza una vez por redirect y pasa props:
| Prop | Contenido |
|---|---|
from | Ruta origen |
to | Ruta destino |
status | Código de estado |
delay | Segundos de espera |
---
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>El meta refresh es el redirect
En build estático tu página debe renderizar un
<meta http-equiv="refresh">que apunte ato. Astro avisa si falta y cae al page built-in si el tuyo falla. Los redirects de páginas on-demand no cambian.
🧩 Otras mejoras
- Integraciones controlan el output: Astro trata el
outDirresuelto por Vite para cada entorno como fuente de verdad de dónde se escribe client, server y prerender. Las integraciones y plugins de Vite pueden moverlo. outputDirectories: nuevo contexto ensetPrerenderer()para que los prerenderers custom lean las ubicaciones finales.- Build manifests: los manifiestos de Vite se conservan hasta que terminan todos los hooks
buildApp, para que las integraciones de deploy puedan leerlos (#18313).
⚠️ Notas prácticas
- Node 22.22.0 es el nuevo piso; revisar CI y contenedores antes de actualizar.
--timingsno optimiza solo: identifica el cuello; el fix sigue siendo tuyo.- Imagen split: si mantienes una integración que lee
config.image.service.entrypoint, añade el check deruntime. - Adapters: actualizar
@astrojs/cloudflarey@astrojs/markdoca la par deastro@^7.4.0. - Experimentales:
parallelPrerenderyredirectPagepueden cambiar; no los uses en producción sin probar. - Memoria: el prerender paralelo multiplica el consumo; medir con
--timingsy ajustarworkers.
🔗 Enlaces relacionados
- ⚡ Vite+ — toolchain y build para frontend moderno.
- 🚀 Dokploy — despliegue self-hosted de sitios Astro.
- 📊 CodeGraph — explorar el repo de Astro o tu proyecto.
- Astro (stack del curso) — notas base del stack.
- 📥 Vault Ingest — cómo se guardó esta nota.