Islands architecture: cómo funciona y por qué está ganando terreno
Hidratar toda una aplicación para que un botón funcione es el problema que la arquitectura de islas vino a resolver. Cómo funciona por dentro, cómo la implementa Astro y qué se pierde a cambio de lo que se gana.
Durante años, construir una página con “un poco de interactividad” con un framework como React o Vue significaba una cosa: enviar el framework completo al navegador, aunque el 95% de la página fuera texto estático. Un blog con un botón de “me gusta” cargaba el mismo runtime que una aplicación de gestión de inventario. La arquitectura de islas nace de una pregunta simple: si solo una pequeña parte de la página necesita JavaScript, ¿por qué hidratamos toda la página?
El problema: hidratación total en una SPA
En el modelo clásico de una Single Page Application, el servidor (si lo hay) envía HTML pre-renderizado, pero el navegador tiene que “despertar” ese HTML ejecutando el framework completo sobre el árbol entero del DOM: reconstruir el virtual DOM, adjuntar event listeners, inicializar el estado de cada componente. Esto se llama hidratación, y es un proceso que consume CPU proporcionalmente al tamaño de la página, no a la cantidad de interactividad real que contiene.
El síntoma más visible de este problema es el tiempo hasta interactividad: una página puede pintarse rápido (buen First Contentful Paint) pero seguir bloqueada para el usuario mientras el hilo principal está ocupado hidratando componentes que ni siquiera son visibles todavía. Esto afecta directamente a métricas como el INP de Core Web Vitals: un botón puede estar pintado en pantalla y no responder al primer clic porque su event listener aún no se ha adjuntado.
La idea central: islas de interactividad en un océano estático
El término “islands architecture” lo popularizó Katie Sylor-Miller en 2019 y lo desarrolló después Jason Miller (creador de Preact), pero fue Astro quien lo llevó a un framework completo de uso mainstream a partir de 2021. La idea: en lugar de tratar la página como una única aplicación monolítica, la tratas como HTML estático con “islas” independientes de interactividad incrustadas dentro. Cada isla es un componente autocontenido con su propio ciclo de hidratación, aislado del resto.
El océano —todo lo que no es una isla— nunca ejecuta JavaScript de framework. Sigue siendo HTML y CSS puros. Esto no es un detalle de optimización menor: es la razón por la que una página de Astro sin islas puede pesar 0 KB de JavaScript de framework, algo estructuralmente imposible en una SPA tradicional aunque optimices al máximo con code splitting.
graph TD P[Página HTML estática] --> I1[Isla: buscador] P --> I2[Isla: carrusel de imágenes] P --> I3[Isla: formulario de newsletter] I1 -->|client:load| H1[Hidrata inmediatamente] I2 -->|client:visible| H2[Hidrata al entrar en viewport] I3 -->|client:idle| H3[Hidrata cuando el navegador está libre]
Cómo lo implementa Astro por dentro
Astro compila cada componente .astro, .jsx, .vue o .svelte a HTML estático por defecto. El JavaScript del componente solo se incluye en el bundle final del cliente si tú añades explícitamente una directiva client:* al usarlo:
---
import Buscador from '../components/Buscador.jsx';
import Carrusel from '../components/Carrusel.jsx';
---
<Buscador client:load />
<Carrusel client:visible />
Cada directiva define una estrategia de carga distinta:
client:load: hidrata en cuanto la página termina de cargar. Para interactividad crítica visible desde el primer momento.client:idle: espera a que el navegador esté inactivo (usarequestIdleCallbackinternamente). Para componentes importantes pero no urgentes.client:visible: hidrata solo cuando el componente entra en el viewport (usaIntersectionObserver). Ideal para contenido “below the fold” como carruseles o widgets al final de la página.client:media: hidrata condicionalmente según una media query, útil para componentes que solo son interactivos en ciertos tamaños de pantalla (un menú hamburguesa en móvil, por ejemplo).client:only: se salta el renderizado en servidor por completo y renderiza directamente en cliente; se reserva para componentes que dependen de APIs exclusivas del navegador.
Cada isla se hidrata de forma independiente y en paralelo respecto a las demás. Esto significa que una isla lenta —por ejemplo, un widget que depende de una librería pesada de gráficos— no bloquea la hidratación de una isla ligera y más urgente como un botón de menú, algo que en una SPA monolítica sí ocurriría porque toda la hidratación compite por el mismo hilo principal de forma acoplada.
Server Islands: extender la idea al servidor
Astro amplió después el concepto con Server Islands: en lugar de diferir la carga de JavaScript en el cliente, diferís la ejecución de una parte del renderizado en el servidor. Con la directiva server:defer, una porción de la página que depende de datos personalizados por usuario —un saludo con el nombre, un carrito de compra, contenido geolocalizado— se renderiza en una petición separada que no bloquea el resto del HTML estático. El navegador recibe primero el “cascarón” estático con un placeholder, y esa petición diferida rellena el hueco poco después, normalmente sin apenas percepción de retraso si el servidor responde rápido.
Esto resuelve un problema real: antes de Server Islands, cualquier fragmento de contenido personalizado obligaba a marcar toda la ruta como dinámica (server-rendered), perdiendo los beneficios de cacheabilidad del resto de la página aunque el 95% del contenido fuera idéntico para todos los usuarios.
Trade-offs reales: lo que se gana y lo que cuesta
Se gana:
- JavaScript proporcional a la interactividad real, no al tamaño de la página.
- Resiliencia: si el JavaScript de una isla falla, el resto de la página sigue siendo HTML funcional (progressive enhancement por diseño).
- Tiempo hasta interactividad drásticamente mejor en páginas mayoritariamente estáticas.
- Cacheabilidad: el HTML estático se sirve desde CDN sin coste de cómputo, incluso en páginas con islas.
Cuesta:
- Coordinación de estado entre islas: si dos islas necesitan compartir estado (un contador en el header que refleja un carrito actualizado en otra isla), no hay un árbol de componentes común que lo resuelva de forma nativa. Astro recomienda soluciones como nanostores (un gestor de estado minimalista pensado justamente para este escenario) o eventos del DOM, pero es trabajo adicional que en una SPA con estado global no existe.
- Decisión manual por componente: cada isla requiere que el desarrollador decida explícitamente su estrategia de hidratación. Es más control, pero también más superficie de decisión y de error: olvidar una directiva, o elegir
client:loadpor defecto para todo, anula buena parte del beneficio. - No resuelve bien aplicaciones con mucha interactividad interconectada: si la mayoría de la página son islas que se comunican constantemente entre sí, el modelo empieza a parecerse a una SPA pero sin las herramientas maduras de gestión de estado que un framework como React ya tiene. En ese escenario, forzar islands architecture suele ser peor que aceptar que el proyecto es, en realidad, una aplicación.
Dónde encaja y dónde no
Islands architecture rinde al máximo en sitios donde el contenido domina y la interactividad es puntual: blogs, documentación, e-commerce con fichas de producto mayormente estáticas y un carrito acotado, sitios de marketing con formularios sueltos. Es la base técnica que hace que Astro compita tan bien contra frameworks app-first como Next.js en ese tipo de proyecto.
No es el modelo adecuado para dashboards, editores en tiempo real, o cualquier aplicación donde la mayor parte de la pantalla es estado interconectado que cambia constantemente. Ahí, la hidratación total de una SPA (o el modelo de Server Components de React, que resuelve un problema distinto pero relacionado) sigue siendo la herramienta correcta, no porque islands architecture esté “mal”, sino porque resuelve un problema —minimizar JavaScript en páginas mayoritariamente estáticas— que esas aplicaciones no tienen.
El framework no determina la arquitectura; la arquitectura determina qué framework tiene sentido. Islands architecture ganó terreno porque hizo visible algo que llevaba años siendo un coste invisible: la mayoría del JavaScript que enviábamos a producción no tenía nada que ver con la interactividad real que el usuario necesitaba.
Artículos relacionados
Optimización de imágenes en la web moderna: formatos, lazy loading y CDN
Formatos de imagen, srcset/sizes, lazy loading nativo y CDN de transformación on-the-fly: la guía técnica completa para dejar de servir imágenes de más.
WCAG 2.2 explicado: la guía práctica de accesibilidad web para developers
Los 9 criterios nuevos de WCAG 2.2 explicados sin jerga, qué nivel de conformidad te exige realmente la ley y cómo auditar tu web con herramientas reales.
Gestión de estado en aplicaciones frontend modernas: guía práctica
La pregunta '¿qué librería de estado uso?' suele estar mal planteada. Antes hay que responder otra: ¿qué tipo de estado es este? Local, global o de servidor piden soluciones distintas, y la mitad de las veces la respuesta correcta es no añadir ninguna librería.