Overview
An island is a framework component (React, Preact, Solid, Svelte, or Vue) that Astro renders to HTML and then hydrates on the client when a client:* directive fires. Everything outside an island is inert HTML. A component with no directive renders once, at build time or request time, and ships no JavaScript; that is the right default for display-only components. See hydration for the term.
Pick the directive by when the user needs it
| Directive | Hydrates | Use for |
|---|---|---|
client:load | immediately on page load (high priority) | above-the-fold controls touched at once: theme toggle, sticky search, auth button |
client:idle | after load, on requestIdleCallback; optional timeout | non-critical widgets: newsletter form, share button |
client:visible | when it enters the viewport (IntersectionObserver); optional rootMargin | below-the-fold islands: comments, charts, media players, demos |
client:media="(max-width: 768px)" | when the media query matches | mobile drawer, swipe carousel |
client:only="react" | client only, never server-rendered | components that need window on mount |
Use client:visible as the default for anything below the fold, and do not default to client:load. client:only requires the framework name (react, preact, svelte, vue, solid-js) and supports a slot="fallback". Do not use it to hide hydration errors in components that can render on the server; fix the component, because client:only costs a layout flash.
<ThemeToggle client:load />
<CommentsSection client:visible />
<MobileMenu client:media="(max-width: 768px)" />Share state between islands with a store
Islands are isolated roots, so React context does not cross them. Share state with a framework-agnostic store; Astro recommends Nano Stores. Keep one framework per page where you can, because each framework on a page ships its own runtime.
Keep a JavaScript budget per page
Build, then inspect dist/_astro/ and the page HTML to see which islands ship which scripts; see astro-performance. If a component has no state, effects, or browser API use, rewrite it as .astro and drop the framework cost. Prefer client:visible and client:idle over client:load to defer runtime parsing.
Use server islands to defer personalized content
server:defer turns an Astro component into a server island that renders on demand while the rest of the page stays static and cacheable. It needs an on-demand adapter (see astro-ssr). The island can read cookies and fetch data like any server-rendered component, and a named slot="fallback" shows placeholder content while it loads.
<Avatar server:defer>
<GenericAvatar slot="fallback" />
</Avatar>Props must be serializable (plain objects, arrays, Date, Map, Set, URL, typed arrays; no functions) and are encrypted into a GET request that browsers and CDNs can cache with Cache-Control. Above 2048 bytes Astro switches to POST, which is not cached. Astro generates an encryption key per build; with rolling deployments or multiple regions, create a stable one with astro create-key and set it as ASTRO_KEY.