What is an Island?
In a React or Next.js app the browser receives one large JavaScript bundle. React boots up, walks the entire component tree, and attaches event listeners everywhere — even on components that never do anything interactive. This is full-app hydration.
The Island Architecture, coined by Jason Miller and popularised by Astro, inverts the default: pages are inert HTML. Only the components that need interactivity are hydrated, and they hydrate independently — like islands in a sea of static markup.
The hydration cost in React vs Astro
Section titled “The hydration cost in React vs Astro”// Next.js page — the WHOLE tree hydrates.// Even <Header> and <Footer> download JS.export default function BlogPost({ post }) { return ( <> <Header /> {/* JS downloaded + hydrated */} <article>{post.content}</article> {/* JS downloaded + hydrated */} <LikeButton postId={post.id} /> {/* JS downloaded + hydrated */} <RelatedPosts posts={post.related} />{/* JS downloaded + hydrated */} <Footer /> {/* JS downloaded + hydrated */} </> );}// Total JS budget: EVERYTHING---// Astro page — only <LikeButton> needs JS.import Header from '../components/Header.astro';import LikeButton from '../components/LikeButton.jsx';import RelatedPosts from '../components/RelatedPosts.astro';import Footer from '../components/Footer.astro';const { post } = Astro.props;---<Header /> <!-- 0 KB JS --><article>{post.content}</article> <!-- 0 KB JS --><LikeButton client:visible postId={post.id} /> <!-- hydrated --><RelatedPosts posts={post.related} /> <!-- 0 KB JS --><Footer /> <!-- 0 KB JS -->{/* Total JS budget: ONE component */}On a typical content page — a blog post, a landing page, a docs site — the vast majority of components are purely presentational. They display data; they never respond to clicks. Hydrating them wastes CPU and delays Time to Interactive.
The performance win
Section titled “The performance win”Astro measures this precisely. A page with a single LikeButton island only downloads the JavaScript for that button and its React runtime — nothing else. A Next.js equivalent ships React plus every component on the page.
Typical real-world results on content-heavy sites:
- 90%+ reduction in JavaScript shipped
- Faster Largest Contentful Paint — the HTML arrives parsed, no hydration blocking rendering
- Lower Time to Interactive — only one small island needs to boot
What “partial hydration” means
Section titled “What “partial hydration” means”The pattern is called partial hydration because only a part of the page is hydrated. Each island:
- Renders to HTML on the server/build (like any
.astrocomponent) - Ships its own JS bundle to the browser
- Hydrates independently — islands do not share a React root
That last point matters: islands are isolated. There is no single React tree connecting them, which means no shared React context across islands by default. You will learn how to work with that in When to Use an Island.
// React: ONE root, one reconciler, shared contextimport ReactDOM from 'react-dom/client';ReactDOM.createRoot(document.getElementById('root')) .render(<App />);// Every component inside <App> is part of this tree.// React.createContext() works across the whole tree.---// Astro: MULTIPLE roots, one per island// Astro mounts each island independently:// ReactDOM.createRoot(islandEl).render(<Counter />)// ReactDOM.createRoot(likeEl).render(<LikeButton />)// Each island has its own React root.// React.createContext() does NOT cross island boundaries.import Counter from '../components/Counter.jsx';import LikeButton from '../components/LikeButton.jsx';---<Counter client:load /><LikeButton client:visible postId={42} />