# Island hydration strategies in Astro

The client directive is a budget choice: load, idle, visible, media or only decide when an island downloads its JavaScript and what the page costs.

> Page: https://ui.eneawork.it/blog/astro-islands-hydration-strategie
> Markdown: https://ui.eneawork.it/blog/astro-islands-hydration-strategie.md

*2026-11-01*

In Astro la strategia di idratazione è una scelta di budget: si prende la direttiva più economica che porta il contenuto interattivo prima che l’utente lo tocchi, e si misura quanto JavaScript aggiunge.

## Il costo di ogni direttiva

Le direttive accettano un valore: client:idle con timeout mette un tetto all’attesa e client:visible con rootMargin anticipa il caricamento di 200 pixel, così l’isola è pronta quando arriva sullo schermo.

--- import Search from "../components/Search.jsx"; import Gallery from "../components/Gallery.jsx"; ---

## Si misura sulla build, non a occhio

La build elenca un file per isola: il numero da guardare è il peso del chunk dell’isola sommato a quello del runtime del suo framework, non il totale della pagina.

npm run build ls -lh dist/_astro/*.js

Misurato il 1 novembre 2026 sul build del client EneUI: 48 file JavaScript per 523.037 byte, cioè 510,8 KB, con i due chunk più grandi a 141.671 e 141.302 byte. Metodo: Get-ChildItem client/dist -Recurse -Filter *.js | Measure-Object -Sum Length, eseguito sul repository.

Quel totale non è un tetto per una pagina Astro: è il costo di un’applicazione interamente idratata. La differenza utile è quella fra due build della stessa pagina, una con l’isola e una senza, perché il runtime del framework si paga una volta e non per componente.

## Quando l’isola non serve

Un blocco che si apre e si chiude non è un’isola: <details> fa lo stesso senza JavaScript. Un form che invia dati funziona con una form action. L’isola entra quando serve stato che il server non può calcolare.

## Isola server, zero JavaScript

--- import UserGreeting from "../components/UserGreeting.astro"; --- Hello, guest.

server:defer sposta l’HTML dell’isola in una richiesta separata: la pagina arriva subito con il fallback e il contenuto lo sostituisce quando è pronto. Non c’è idratazione, quindi nessun runtime, ma c’è una richiesta in più e un fallback visibile che va progettato.

## Il tetto da tenere

Una pagina con tre isole dello stesso framework paga il runtime una volta sola ma tre componenti. Se la somma supera quella di un unico widget conviene fondere le isole, perché il confine costa più del codice.

## La regola di decisione

Regola: parti da client:visible; scendi a client:idle quando il widget deve essere pronto prima che l’utente lo raggiunga, come una ricerca in testata; tieni client:load per il solo controllo che sta nella prima schermata e riceve un click immediato. client:only resta per il codice che non può girare sul server.

Il confine ha un prezzo fisso: due isole dello stesso framework scaricano il runtime una volta e due componenti, ma ognuna aggiunge un punto di ingresso e un ordine di esecuzione da verificare. Sopra le quattro isole in una pagina conviene chiedersi se il widget non sia uno.

Misurato il 1 novembre 2026: su 1.514 profili di libreria del catalogo 4 riguardano Astro e solo uno dichiara una licenza, MIT; saastro, starseam e contentbit rimandano al sito del progetto. Metodo: conteggio dei campi id e license di data/library_profiles.json con uno script Node, sul repository EneUI.

## Il limite da mettere in conto

client:visible si appoggia a IntersectionObserver: un’isola dentro un contenitore display: none o in una scheda chiusa non entra mai nel viewport e non idrata. Serve client:load oppure idratare al primo click sulla scheda.

## Errori che si vedono

Le isole si riempiono con componenti pronti: saastro e Astro Association si installano come sorgente, e il blocco hero resta statico finché non riceve una direttiva. L’elenco delle direttive è in isole interattive in Astro, il caso in cui l’idratazione manca in client directive mancante, il confronto in Astro vs Next.js.

## FAQ

### Quale direttiva scelgo per un widget sopra la piega?

client:load. Sopra la piega il widget entra nel viewport subito, quindi client:visible non risparmia nulla e aggiunge un giro di IntersectionObserver prima del caricamento.

### client:idle ha un timeout massimo?

Sì, si passa come valore e senza di esso l’idratazione aspetta il primo momento libero, che su una pagina pesante può arrivare tardi. Un timeout di 500 millisecondi mette un tetto prevedibile.

### Perché due isole non condividono lo stato?

Perché ognuna è un’applicazione separata con il proprio componente e il proprio stato. Per condividere dati serve uno store esterno, come nanostores, sottoscritto da entrambe.

### Il framework runtime viene duplicato?

No, il codice condiviso del framework finisce in un chunk comune alle isole dello stesso tipo. Restano separati i componenti, che sono la parte che scrivi tu.

### client:visible funziona nelle schede?

Solo quando la scheda è visibile: un pannello nascosto non interseca il viewport. Per quel caso conviene client:load sul pannello che si apre, oppure un’idratazione manuale al click.
