Skip to main content
Astro pioneered and popularized the islands architecture pattern. This approach allows you to build fast, content-focused websites while maintaining the ability to add interactive UI components where needed.

What is Islands Architecture?

Islands architecture is a component-based architecture where interactive components (islands) are embedded within otherwise static HTML pages. Think of your page as an ocean of static HTML with scattered islands of interactivity.
Key Concept: Only the interactive components are shipped to the client as JavaScript, while the rest of the page remains static HTML. This dramatically reduces the amount of JavaScript sent to the browser.

How It Works

By default, Astro renders all components to static HTML on the server with zero client-side JavaScript. When you need interactivity, you opt-in using client directives.
---
import Counter from '../components/Counter.jsx';
import Navigation from '../components/Navigation.astro';
---

<Navigation />
<h1>Welcome to my site</h1>
<Counter client:load />
In this example:
  • Navigation renders as static HTML (no JavaScript)
  • Counter becomes an interactive island that hydrates on the client

Client Directives

Client directives tell Astro when and how to hydrate your interactive components. These directives are added as attributes to your component tags.

client:load

Hydrates the component immediately on page load.
<InteractiveHeader client:load />
Use client:load for high-priority UI that needs to be interactive immediately, like a navigation menu or chat widget.

client:idle

Hydrates the component when the browser is idle (uses requestIdleCallback).
<CommentSection client:idle />
This is the recommended directive for most interactive components. It waits until the main thread is free before hydrating.
Ideal for lower-priority UI that doesn’t need to be immediately interactive, like comment sections, social media embeds, or analytics widgets.

client:visible

Hydrates the component when it enters the viewport (uses IntersectionObserver).
<ImageCarousel client:visible />
Perfect for components below the fold, like image carousels, infinite scroll loaders, or any content that might not be immediately visible.

client:media

Hydrates the component when a CSS media query matches.
<MobileMenu client:media="(max-width: 768px)" />
Useful for components that only make sense at certain screen sizes, like mobile-specific navigation or desktop-only features.

client:only

Skips server-side rendering and only renders the component on the client.
<BrowserOnlyWidget client:only="react" />
Use this sparingly! It opts out of Astro’s server-side rendering benefits. Only use for components that have browser-only dependencies or cannot run on the server.
You must specify which framework to use:
<ReactComponent client:only="react" />
<VueComponent client:only="vue" />
<SvelteComponent client:only="svelte" />

Practical Example

Here’s a complete page showing different hydration strategies:
---
import Header from '../components/Header.astro';
import Hero from '../components/Hero.jsx';
import Newsletter from '../components/Newsletter.jsx';
import Comments from '../components/Comments.jsx';
import Analytics from '../components/Analytics.jsx';
import Footer from '../components/Footer.astro';
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>My Page</title>
  </head>
  <body>
    <!-- Static HTML, no JavaScript -->
    <Header />
    
    <!-- Hydrate immediately for critical interactivity -->
    <Hero client:load />
    
    <!-- Hydrate when visible -->
    <Newsletter client:visible />
    
    <!-- Hydrate when browser is idle -->
    <Comments client:idle />
    
    <!-- Only on mobile -->
    <Analytics client:media="(max-width: 768px)" />
    
    <!-- Static HTML -->
    <Footer />
  </body>
</html>

Benefits

Faster Performance

Less JavaScript means faster page loads and better Core Web Vitals scores.

Better SEO

Content is rendered as HTML on the server, making it immediately crawlable by search engines.

Progressive Enhancement

Pages work with JavaScript disabled, then enhance when it loads.

Framework Agnostic

Mix React, Vue, Svelte, and other frameworks on the same page.

Technical Implementation

Astro wraps hydrated components in custom <astro-island> elements. From the source code (src/runtime/server/hydration.ts), the system:
  1. Extracts client directives from component props
  2. Validates the directive is supported
  3. Generates hydration metadata
  4. Wraps the component in an <astro-island> with hydration instructions
// Simplified from src/runtime/server/hydration.ts
export function extractDirectives(inputProps: Props) {
  let extracted = {
    hydration: null,
    props: {},
  };
  
  for (const [key, value] of Object.entries(inputProps)) {
    if (key.startsWith('client:')) {
      extracted.hydration = {
        directive: key.split(':')[1],
        value: value,
      };
    } else {
      extracted.props[key] = value;
    }
  }
  
  return extracted;
}

Best Practices

1

Start with static

Default to Astro components (.astro files) which render as static HTML.
2

Add interactivity selectively

Only use framework components (React, Vue, etc.) where you need client-side interactivity.
3

Choose the right directive

  • client:load for critical UI
  • client:idle for most interactive components
  • client:visible for below-the-fold content
  • client:media for responsive components
  • client:only as a last resort
4

Measure the impact

Use browser DevTools to see how much JavaScript each directive loads.

Learn More

Components

Learn about Astro’s component model

Routing

Understand Astro’s file-based routing

Build docs developers (and LLMs) love