Qué son las server islands y qué resuelven
El dilema entre una página cacheable y un trozo personal: durante años, un solo fragmento dinámico —el avatar, el carrito— obligaba a renderizar toda la página en el servidor y a renunciar al caché. Las server islands invierten el planteamiento: la página sigue siendo estática y solo el fragmento variable se aplaza a una petición aparte con server:defer, acotando lo dinámico a un recuadro.
La arquitectura de islas del nivel 16 aislaba JavaScript: un mar de HTML inerte con pequeñas islas interactivas. Las server islands trasladan esa misma idea al otro lado del cable. Ahora el mar es una página estática, cacheable byte a byte en un CDN, y las islas son fragmentos que el servidor renderiza bajo demanda —el saludo con tu nombre, el contador del carrito, un precio que cambia cada minuto—. La misma disciplina, aislar lo variable de lo estable, aplicada al eje del momento de render en lugar del eje del JavaScript.
- Reconocer el dilema entre una página cacheable y un fragmento personalizado.
- Entender qué es una server island y cómo
server:deferla declara. - Ver la analogía con las islas de cliente: el mismo patrón sobre otro eje.
- Saber qué exige el patrón —un adaptador— y qué te devuelve —caché íntegro—.
El dilema entre lo cacheable y lo personal
Una página web quiere dos cosas que, hasta hace poco, eran incompatibles. Por un lado, ser estática: horneada una vez, servida como un fichero plano desde el borde de la red, con un TTFB mínimo y una factura de servidor cercana a cero.
Por otro, ser personal y fresca: saludarte por tu nombre, mostrar tu carrito, reflejar el precio de este segundo. Lo primero pide inmovilidad; lo segundo, cambio en cada visita.
En los niveles anteriores esa tensión se resolvía por página. prerender decidía, ruta a ruta, si algo se horneaba en el build o se renderizaba bajo demanda. Pero esa decisión era de grano grueso, y ahí estaba la tragedia: un solo byte dinámico contaminaba la página entera.
Si la cabecera dice “Hola, Ana”, la página ya no puede compartirse en un caché público; y para pintar esa cabecera te veías obligado a poner prerender = false y a re-renderizar en cada petición el artículo de tres mil palabras que no cambia nunca.
Se tiraba el caché del 99 % estable para atender al 1 % variable.
Esa coacción del todo-o-nada tiene una raíz histórica. Los modos de salida nacieron pensando en documentos homogéneos —o una página es un artículo inmutable, o es un panel que cambia entero—, y esa homogeneidad casi nunca describe una página real, que suele ser un noventa por ciento de contenido perenne salpicado de unos pocos datos vivos.
Forzar una única política de render sobre esa mezcla es como fijar la temperatura de una casa entera según la habitación más exigente: o malgastas o pasas frío, nunca aciertas para todas.
Antes de las server islands, la personalización más trivial —un nombre en la esquina— degradaba una página estática a una página de servidor. No había término medio: o toda la página era cacheable o ninguna parte lo era. Las server islands existen precisamente para disolver esa falsa disyuntiva y devolver el grano fino a una decisión que llevaba demasiado tiempo siendo tosca.
La directiva server:defer
Una server island se declara con una sola marca. Añades server:defer a un componente .astro y Astro lo saca del render de la página: la página se genera sin él, dejando en su lugar un hueco, y ese componente se renderiza aparte, en el servidor, en el momento de cada visita.
---
// src/pages/index.astro (puede prerenderizarse)
import Saludo from '../components/Saludo.astro';
---
<header>
<h1>Mi tienda</h1>
<Saludo server:defer />
</header>
<article>
...miles de palabras de HTML puro que se cachean intactas...
</article>
Saludo es un componente Astro corriente: no cambia nada dentro de él. Lo único nuevo es la directiva. Esa página puede prerenderizarse y cachearse por completo, porque la única parte que depende del visitante —el saludo— ya no vive en su HTML: vive en una isla que se llenará después.
La invasión de lo dinámico queda acotada a un recuadro, en vez de teñir el documento entero.
Conviene precisar qué puede ser una server island: un componente .astro que se renderiza en el servidor bajo demanda. No es una isla de cliente ni necesita JavaScript propio; es HTML generado por petición.
Puedes anidar islas de cliente dentro de ella —un botón interactivo dentro del menú diferido—, pero server:defer gobierna el cuándo se renderiza en el servidor, no el cuándo se hidrata en el cliente. Son dos ejes ortogonales, y una de las señales de madurez en Astro es saber combinarlos sin confundirlos.
Islas en el servidor: el mismo patrón, otro eje
Merece la pena ver hasta qué punto esto es la misma idea del nivel 16, girada noventa grados. Una isla de cliente es un hueco en un HTML estático que se rellena con JavaScript en el navegador. Una isla de servidor es un hueco en un HTML estático que se rellena con una petición al servidor.
En ambos casos el documento es, por defecto, estático e inerte, y la interactividad o el dinamismo se declaran región a región, pagando su coste solo donde se pide.
Isla de cliente
Hueco en HTML estático que se hidrata con JS en el navegador. Aísla el coste de JavaScript. Directiva client:*.
Isla de servidor
Hueco en HTML estático que se llena con una petición al servidor. Aísla el coste de render por visita. Directiva server:defer.
El cascarón
Todo lo demás: HTML puro, horneado una vez, cacheable en el CDN. Ni JS ni render por petición.
flowchart LR U[navegador pide la pagina] --> CDN[CDN sirve HTML estatico cacheado] CDN --> HOLE[la pagina trae el hueco y el fallback] HOLE --> REQ[el navegador pide la isla aparte] REQ --> SRV[el servidor renderiza la isla por peticion] SRV --> SWAP[el fragmento reemplaza al fallback] style CDN fill:#a6e3a1,color:#11111b style SRV fill:#89b4fa,color:#11111b style SWAP fill:#f9e2af,color:#11111b
La analogía llega hasta la topología. Las islas de cliente convirtieron el rendimiento en algo componible: añades una isla y solo pagas su JavaScript, no el de toda la página. Las islas de servidor hacen lo mismo con el render por petición: añades una isla y solo esa parte se computa en vivo, mientras el resto sigue congelado.
En los dos mundos, lo que era una propiedad monolítica del documento —todo hidratado o nada, todo dinámico o nada— se descompone en decisiones locales que se suman sin interferir.
Un mismo fragmento podría ser, a la vez, isla de servidor —para renderizarse fresco por petición— e incluir dentro una isla de cliente —para reaccionar a clics—. El eje del servidor decide cuándo se genera el HTML; el del cliente, cuándo cobra vida ese HTML. Verlos como ejes independientes, y no como alternativas, es la clave para componer páginas ricas sin renunciar al caché.
Qué exige y qué te devuelve
El patrón tiene un requisito: como la isla se renderiza en el momento de la petición, necesitas un adaptador instalado que habilite el render bajo demanda —el mismo que usarías para SSR—. La diferencia crucial con SSR de página completa es que aquí la página anfitriona sigue siendo estática.
No renuncias al caché íntegro para ganar dinamismo; conservas ambos.
Ese y es la palabra clave: no es una permuta entre velocidad y frescura —renunciar a una por la otra—, sino la conjunción de ambas sostenida en una sola URL.
Compáralo con las dos alternativas de siempre. Pasar toda la página a servidor te da el dato fresco pero pierde el caché del borde y encarece cada visita.
Ir a buscar el dato con un fetch desde el cliente conserva el caché pero te obliga a exponer un endpoint público, sufre una cascada tras cargar el JavaScript y deja ese fragmento fuera del HTML inicial.
La server island es la tercera vía: caché completo de la página, render en el servidor —sin API pública que mantener— y aislamiento del trozo variable.
La elección, por tanto, no es entre estático y dinámico, sino entre tres topologías de coste. SSR de página completa mueve el coste a cada petición y sacrifica el borde. El fetch de cliente conserva el borde pero paga con una cascada y una superficie de API expuesta.
La server island conserva el borde y evita la API, y a cambio acepta un segundo viaje acotado y la maquinaria de cifrado que veremos en la lección de internals. Ninguna es gratis; cada una coloca el coste en un lugar distinto, y elegir bien es saber qué lugar puede permitírselo tu página.
Tres topologías, tres facturas distintas:
- SSR de página completa: coste en cada petición, sin caché de borde.
fetchde cliente: caché intacto, pero con cascada y una API pública que proteger.- Server island: caché intacto y sin API, a cambio de un segundo viaje y el cifrado de props.
No hay una ganadora universal; hay una adecuada para cada fragmento.
Un error de encuadre habitual es pensar que usar server islands convierte todo el proyecto en SSR. No: instalas un adaptador para que exista la capacidad de renderizar bajo demanda, pero tus páginas pueden seguir prerenderizándose una a una. Solo las islas se resuelven por petición.
La mejor forma de descubrir dónde te sirven las server islands es mirar tus páginas dinámicas y preguntarte qué las obligó a serlo. Muchas veces la respuesta es un único fragmento —un saludo, un carrito—. Ese fragmento es tu primera server island, y extraerlo suele bastar para devolver toda la página al reino de lo cacheable.
El arco de todo este trayecto ha sido refinar la pregunta “¿cuándo se calcula esto?” hasta un grano cada vez más fino. Primero era una propiedad del proyecto entero: estático o servidor. Luego prerender la bajó al nivel de la ruta: esta página se hornea, aquella se resuelve al vuelo. Las server islands dan el paso final y la bajan al componente: dentro de una misma URL, el cascarón se calcula una vez y se cachea para todos, mientras la isla se calcula de nuevo para cada visitante. Una sola página pasa a habitar dos regímenes temporales a la vez —lo perenne y lo instantáneo— sin que uno contamine al otro. Esto es la arquitectura de islas alcanzando su forma general: no la descomposición de una página por su interactividad, ni siquiera por su JavaScript, sino por el ritmo al que cambia cada una de sus partes. Cuando interiorizas que cada fragmento tiene su propia cadencia de cambio, dejas de preguntarte “¿esta página es estática o dinámica?” —una pregunta mal planteada— y empiezas a preguntarte, fragmento a fragmento, con qué frecuencia cambia y quién lo mira. Esa es la lente que gobierna el resto del nivel, y es también la razón por la que las server islands no son una función más de Astro sino la consecuencia natural de tomarse en serio, hasta el final, la idea de que una página es un archipiélago y no un continente.
- Toma una página casi toda estática con una cabecera personalizada: un blog cuyo encabezado saluda al usuario registrado.
- Describe qué pasaría hoy si la personalizas con
prerender = false: ¿qué caché pierdes y por qué? - Ahora describe la vía del
fetchde cliente: ¿qué endpoint tendrías que exponer y qué cascada aparece? - Convierte la cabecera en una server island con
server:defery razona por qué la página vuelve a ser cacheable por completo. - Enumera, en esa misma página, otros dos fragmentos que podrían volverse islas y clasifícalos por su cadencia de cambio.