El problema que Astro resuelve
Las SPAs envían la aplicación entera al navegador y pagan el coste de la hidratación. Para un sitio de contenido —un blog, unas docs, un landing— eso es desperdicio puro. Este es el problema del que nace Astro.
Durante una década, la respuesta por defecto a “necesito una web” fue una SPA en React. Pero la tesis de un blog, una página de documentación o un landing de marketing no son aplicaciones: son documentos. Enviar el motor completo de una aplicación para pintar texto es el desperdicio silencioso que Astro nace para eliminar.
- Entender el modelo de renderizado de una SPA y su coste real.
- Comprender qué es la hidratación y por qué bloquea el hilo principal.
- Medir el desperdicio con métricas objetivas: TTI, TBT y kilobytes de JS.
- Distinguir una “aplicación” de un “sitio de contenido” y por qué la distinción lo cambia todo.
La SPA: la aplicación entera, en el cliente
Una Single Page Application traslada el renderizado al navegador. El servidor entrega un HTML casi vacío —un contenedor <div id="root">— acompañado de un bundle de JavaScript que contiene el framework, el router, el árbol de componentes y toda la lógica. El navegador descarga ese bundle, lo analiza, lo compila y lo ejecuta antes de poder pintar nada útil.
<!-- Lo que el servidor de una SPA pura envía de verdad -->
<body>
<div id="root"></div>
<script type="module" src="/assets/index-a3f9.js"></script>
</body>
El usuario mira una página en blanco hasta que ese index.js termina de ejecutarse. En una conexión lenta o un móvil de gama baja, esa espera es real y medible. Todo el contenido —que podría ser HTML estático— depende de que un intérprete de JavaScript lo genere en tiempo de ejecución.
Peor aún, ese proceso es estrictamente secuencial: el navegador no puede pedir el JS hasta leer el HTML, no puede ejecutarlo hasta descargarlo, y no puede pintar hasta ejecutarlo. Es una cadena de dependencias donde cada eslabón espera al anterior —y el usuario espera a todos—.
Bundle monolítico
El framework, sus dependencias y tu código viajan juntos. Un “hola mundo” en React parte de decenas de kilobytes antes de que escribas una línea propia.
Render diferido
Nada aparece hasta que el JS se ejecuta. El HTML no describe la página: solo arranca el motor que la construirá.
Trabajo duplicado
Con SSR, el servidor pinta el HTML y el cliente lo vuelve a construir para “adoptarlo”. El mismo árbol, calculado dos veces.
Coste en el dispositivo
Analizar y ejecutar JS gasta CPU y batería. El coste recae en el cliente del usuario, no en tu servidor.
La hidratación: el impuesto oculto
El renderizado en servidor —SSR o SSG— mejora la primera pintura: el servidor manda HTML ya formado y el usuario ve contenido pronto. Pero ese HTML es inerte: botones que no responden, menús muertos. Para hacerlo interactivo, el framework vuelve a ejecutar en el cliente el mismo árbol de componentes, reconstruye su estado y engancha los manejadores de eventos al DOM existente. Ese proceso se llama hidratación.
Hidratar no es “un poco de JS extra”: es re-ejecutar toda la lógica de renderizado en el hilo principal del navegador —el mismo que procesa clics, scroll y animaciones—. Mientras el hilo está ocupado hidratando, la página parece lista pero no responde. Es el valle inquietante del rendimiento: píxeles visibles, cero interactividad. Cuanto mayor es el árbol de componentes, más largo es el bloqueo.
Dos métricas capturan el daño con precisión:
- TTI (Time to Interactive): cuándo la página responde de verdad. La hidratación lo empuja hacia adelante.
- TBT (Total Blocking Time): cuánto tiempo estuvo bloqueado el hilo principal. Cada tarea larga de hidratación suma milisegundos que el usuario percibe como lag.
Google penaliza ambas dimensiones en Core Web Vitals, y en 2026 siguen pesando en el posicionamiento. El JavaScript que envías no es gratis: lo paga tu usuario en tiempo y tu web en ranking.
Hay incluso un coste que no aparece en ninguna métrica: la fragilidad. Si el JavaScript falla —un error suelto, una red que cae a medias, un navegador que lo bloquea—, una SPA se queda en blanco, porque el contenido dependía de él para existir. Un documento HTML, en cambio, se ve igual aunque el JS no llegue nunca. La robustez sale gratis cuando el contenido no necesita ejecutarse para aparecer.
La anatomía del desperdicio
No todo el peso es igual. Un byte de JavaScript es mucho más caro que un byte de imagen: la imagen se decodifica en hilos secundarios y hardware dedicado; el JavaScript hay que analizarlo, compilarlo a bytecode y ejecutarlo en el hilo principal. Un móvil de gama media puede tardar del orden de un segundo en procesar 300 KB de JS comprimido, antes de que ese código haga nada visible.
La asimetría con los demás recursos es enorme:
- Una imagen se decodifica en hilos aparte y con hardware dedicado.
- El CSS puede retrasar la pintura, pero no bloquea la interactividad.
- El JavaScript hay que descargarlo, analizarlo, compilarlo y ejecutarlo, y todo eso ocurre en el hilo principal.
// El "waterfall" típico de una SPA de contenido
// 1. GET / -> HTML de 2 KB (un div vacio)
// 2. GET /index.js -> 180 KB de framework mas app
// 3. parse y compile -> unos 250 ms de CPU en un movil medio
// 4. execute y render -> construye el DOM que el HTML ya podria traer
// 5. hydrate -> reengancha listeners y dispara el TBT
// Resultado: el usuario ve el texto tarde y lo puede tocar aun mas tarde
Cada paso de ese recorrido es tiempo real en el reloj del usuario, y ninguno era necesario para mostrar un texto: el servidor ya tenía el contenido y podría haberlo mandado como HTML terminado. La SPA cambia una entrega directa por un proceso de cinco fases cuyo único fin es reconstruir, en la máquina más débil de la cadena, algo que la más fuerte ya sabía pintar. Y el reparto de ese coste es profundamente desigual: tú desarrollas en un portátil potente con fibra, pero buena parte de tu audiencia navega desde móviles modestos y redes irregulares. Lo que a ti te parece instantáneo puede costarle segundos a quien te lee.
Reducir el bundle ayuda, pero no ataca la raíz. Aunque comprimas y hagas code-splitting, sigues enviando un framework cuya única misión en una página de contenido es reconstruir en el cliente algo que el servidor ya sabía pintar. El problema no es el tamaño del motor: es que estás enviando un motor. Astro no lo optimiza —lo aparta del camino por defecto—.
Aplicación o documento: la pregunta correcta
Aquí está el nudo. Una aplicación —un editor, un dashboard, una hoja de cálculo— es interactiva de arriba abajo: el coste de la SPA se justifica. Un sitio de contenido no. En un blog, en unas docs o en un landing, el 95% de la página es texto, imágenes y enlaces —contenido que el HTML sabe representar sin una sola línea de JavaScript—. La interactividad, si la hay, es local: un buscador, un carrusel, un menú.
Piénsalo en proporción. En una página de contenido típica, el reparto real suele ser así:
- Texto, encabezados y enlaces: la inmensa mayoría, y HTML puro sin coste alguno.
- Imágenes y multimedia: pesadas en bytes, pero sin coste de hidratación.
- Zonas de verdad interactivas: un puñado de píxeles que sí justifican JavaScript.
flowchart TD subgraph SPA[Sitio de contenido como SPA] A[HTML vacio] --> B[Descargar bundle enorme] B --> C[Ejecutar el framework] C --> D[Hidratar toda la pagina] D --> E[Al fin interactivo] end subgraph IDEAL[Lo que el contenido necesita] F[HTML completo] --> G[Legible al instante] G --> H[JS solo donde hace falta] end style A fill:#f38ba8,color:#11111b style E fill:#f38ba8,color:#11111b style F fill:#a6e3a1,color:#11111b style H fill:#a6e3a1,color:#11111b
Enviar un framework de aplicación para renderizar un artículo es como arrancar un camión para cruzar la calle. Funciona, pero el coste no guarda ninguna proporción con la tarea.
Esto es aplicación
Un dashboard, un editor de texto, una hoja de cálculo, un cliente de correo. Estado por todas partes e interacción constante: aquí el JavaScript se gana su sitio.
Esto es contenido
Un artículo, una guía, una ficha de producto, una landing. Se lee de arriba abajo; la interacción, si la hay, es un detalle puntual.
La prueba del papel
¿Podrías imprimir la página y seguiría teniendo sentido? Si sí, es contenido. Si al imprimirla lo pierde todo, es aplicación.
La mayoría, mixto
Casi toda web real es sobre todo contenido con algo de aplicación. El error caro es tratar ese “algo” como si fuera el todo.
La intuición que lo desbloquea todo: la web nació para documentos, y el HTML sigue siendo la forma más rápida, robusta y accesible de entregar contenido. Una SPA invierte esa premisa —convierte cada documento en una aplicación que debe reconstruirse en el cliente— y luego paga con hidratación el privilegio de deshacer el problema que ella misma creó. Astro parte de la premisa opuesta: el HTML es el destino, no un paso intermedio. Si una página es contenido, se sirve como HTML terminado y no se hidrata nada. El JavaScript deja de ser el cimiento y pasa a ser la excepción puntual. Cuando interiorices esto dejarás de preguntar “¿qué framework uso?” y empezarás a preguntar “¿cuánto de esta página es realmente una aplicación?”. Casi siempre, la respuesta es: mucho menos de lo que creías.
- Abre un blog o unas docs hechas con una SPA (muchos sitios en React lo son) y entra en las DevTools, pestaña Network, filtrando por JS.
- Suma los kilobytes de JavaScript que se descargan solo para leer un artículo de texto.
- En la pestaña Performance, graba la carga y localiza el bloque de “Scripting”: ese es el tiempo de hidratación robado al hilo principal.
- Pregúntate: de todo ese JS, ¿cuánto era realmente interactivo y cuánto era contenido disfrazado de aplicación?