client:only: islas sin servidor y sus riesgos
La directiva que rompe la regla: client:only omite por completo el renderizado de servidor, así que no hay HTML inicial para la isla y hay que declarar el framework a mano porque Astro no puede inferirlo. A cambio de habilitar componentes que solo funcionan en el navegador, se pagan riesgos concretos —salto de layout, ausencia de SEO, destello de vacío— que hay que conocer y mitigar con un fallback.
Qué hace, y por qué pide el framework
Con client:only, Astro trata la isla como puramente de cliente: la omite en el render de servidor y no emite HTML para ella, solo el elemento <astro-island> vacío que el navegador rellenará. Cuando su JavaScript llega, el framework renderiza desde cero —no hidrata, porque no hay marcado previo que reutilizar— y monta el componente en ese hueco.
De ahí sale una peculiaridad de sintaxis obligatoria: tienes que nombrar el framework. Como no hay render de servidor, Astro nunca ejecuta el componente en el build y no puede deducir a qué integración pertenece; se lo dices tú en la directiva.
---import Editor from '../components/Editor.jsx';---<Editor client:only="react" />El valor —"react", "vue", "svelte", "solid-js" o "preact"— identifica el renderer que el cliente debe cargar. Omitirlo es un error de compilación, no un descuido silencioso: sin ese dato, el runtime no sabría qué pegamento de framework importar para dar vida a la isla.
Los tres riesgos
Renunciar al HTML de servidor tiene consecuencias que conviene mirar de frente, porque son justo las que Astro suele evitar.
El primero es el salto de layout. Hasta que el JavaScript llega y renderiza, el espacio de la isla está vacío; cuando el contenido aparece de golpe, empuja lo que tiene alrededor y la página da un brinco. Ese salto degrada el CLS, una de las métricas de Core Web Vitals, y produce esa sensación de página inestable que reacomoda el texto bajo el dedo del usuario.
El segundo es el SEO. Un rastreador que lea el HTML servido no encontrará nada dentro de la isla: ni texto, ni enlaces, ni encabezados, porque ese contenido no existe hasta que se ejecuta el JavaScript. Para cualquier cosa que deba indexarse —un artículo, una ficha de producto, un titular— client:only es una mala elección, porque esconde justo lo que los buscadores necesitan ver.
El tercero es el destello de vacío. Incluso cuando el SEO no importa, el usuario percibe un hueco en blanco que tarda en poblarse, y en conexiones lentas ese vacío puede durar lo suficiente para parecer un error. La interactividad no solo llega tarde: llega después de un intervalo en el que no había absolutamente nada que mirar.
El desajuste como causa raíz
El motivo por el que estos componentes exigen client:only es el desajuste de hidratación. Si Astro los renderizara en el servidor, producirían un HTML —basado en, digamos, un window.innerWidth que en el build no existe— distinto del que el cliente genera al hidratar. El framework detecta esa divergencia y falla ruidosamente. client:only corta el problema de raíz: al no haber HTML de servidor, no hay nada con lo que discrepar. La directiva no es un capricho, sino la respuesta correcta a una incompatibilidad real entre el momento del build y el del navegador.
Cuándo se justifica, y cómo mitigar
client:only existe porque algunos componentes no pueden renderizarse en el servidor. Suelen caer en estos casos:
- Tocan
window,documentolocalStoragenada más montarse. - Miden su contenedor del DOM para dibujarse: un lienzo, un mapa.
- Envuelven una librería que se rompe al ejecutarse fuera del navegador.
- Dependen de una API que solo existe en el cliente.
Para ellos, renderizar en el servidor no es que sea caro, es que no tiene sentido, y client:only es la respuesta correcta. Fíjate en el patrón común: todos necesitan el navegador ya en el primer render, no más tarde en un manejador de eventos. Esa distinción es la línea divisoria: si el navegador solo hace falta al interactuar, la isla puede hidratar de forma normal; si hace falta para dibujar el primer fotograma, client:only es inevitable. Cuando la uses, mitiga sus riesgos con un contenido de fallback: un elemento con slot="fallback" que Astro sí incluye en el HTML inicial y que se muestra hasta que la isla se renderiza. Un esqueleto, un mensaje de carga o —lo más valioso— un bloque del mismo tamaño que el componente final reservan el espacio y suavizan el salto.
---import Mapa from '../components/Mapa.jsx';---<Mapa client:only="react"> <div slot="fallback" class="mapa-placeholder">Cargando mapa…</div></Mapa>Reservar el espacio de antemano
El fallback tapa el destello, pero el salto de layout se combate mejor reservando el hueco con CSS: si el contenedor ya ocupa su tamaño final desde el HTML, la isla se pinta dentro sin empujar a nadie. Una proporción fija o una altura mínima bastan.
.mapa-placeholder { aspect-ratio: 16 / 9; display: grid; place-items: center;}Antes de aceptar ese precio, descarta las señales de que en realidad no la necesitas:
- El componente se renderiza igual en servidor y cliente: usa otra directiva.
- Solo lees
windowdentro de un manejador de eventos, no al montar: puede hidratar normal. - Lo que buscas es contenido dinámico, no interacción: una server island basta.
- El dato que falta en el servidor puede llegar como prop: pásalo y renderiza en servidor.
En 2026 hay además una alternativa que conviene sopesar antes de recurrir a client:only: las server islands con server:defer. Si lo que necesitas es contenido dinámico —personalizado, fresco, dependiente de la petición— pero no interactividad de navegador, una server island lo genera en el servidor y lo inyecta sin enviar JavaScript, dejando el resto de la página cacheable. client:only es para lo que de verdad exige el navegador; para lo que solo es dinámico, casi siempre hay una opción más barata.