frontend / rendering modes / 06_islands_architecture.md

Islands Architecture — Astro, Fresh, Iles

6 min read source

Islands Architecture — Astro, Fresh, Iles

TL;DR

Islands architecture = mostly static HTML with discrete interactive “islands” that hydrate independently. The page ships ~0 KB JS for static content; only the interactive components ship their framework + code. Astro is the production-ready leader; Fresh (Deno), Iles, Marko are alternatives. The senior framing: complementary to React’s RSC + selective hydration — both achieve “interactive bits hydrate, the rest is static.” Pick islands for content-heavy sites (blogs, docs, marketing); pick RSC for app-shaped products.

Interview Q&A

Q: What does an island look like?

A: Astro example:

---
// build/server time
import Counter from "./Counter.tsx";    // React component
import VueChart from "./VueChart.vue";  // Vue component
import { posts } from "./data";
---

<html>
  <head><title>Blog</title></head>
  <body>
    <h1>My Blog</h1>
    <ul>
      {posts.map(p => <li><a href={p.url}>{p.title}</a></li>)}
    </ul>

    <!-- Static — never ships JS -->

    <Counter client:load />            <!-- React island, hydrates immediately -->
    <VueChart client:visible />        <!-- Vue island, hydrates when in viewport -->
  </body>
</html>

The HTML around the islands is rendered at build/server and never hydrates. Only <Counter> and <VueChart> load their framework runtime and component code.

Bundle for a page with 1 React island: ~10 KB (React + tiny runtime). Pure static for the rest. Compare to a full React app: ~40-100 KB minimum.

Q: client:* directives.

A: Astro’s syntax — controls when each island hydrates:

Directive When
client:load immediately on page load
client:idle when the browser is idle (requestIdleCallback)
client:visible when scrolled into viewport (IntersectionObserver)
client:media="(max-width: 600px)" when media query matches
client:only="react" client-only — don’t SSR, render as fallback then hydrate

Each is a different hydration trigger. Use cases:

  • client:load — header search box, immediately interactive.
  • client:visible — below-fold widgets that load when scrolled to.
  • client:idle — analytics opt-in, low-priority interactivity.
  • client:media — mobile-only menu component.
  • client:only — components that touch window and can’t SSR.

This granularity is unique to islands frameworks. React Suspense doesn’t have an equivalent (selective hydration is auto-prioritized, not directive-controlled).

Q: Multi-framework support.

A: Astro can host React + Vue + Svelte + Solid components in the same page. Each island ships only its framework runtime, shared across same-framework islands.

<ReactWidget client:load />
<VueChart client:visible />
<SvelteForm client:idle />

Three runtimes, each loaded only when needed. Useful for:

  • Migrating between frameworks gradually.
  • Using best-fit framework per widget.
  • Adopting Astro for a marketing site without abandoning existing React/Vue components.

Fresh and Iles are Preact-only (Fresh) or Vue-focused (Iles). Astro is the multi-framework standout.

Q: When do islands beat React/Next.js?

A:

Islands win:

  • Content-heavy sites — blogs, docs, marketing, e-commerce catalog browsing.
  • Sites with mostly-static + a few interactive widgets — newsletter signup, search, comments.
  • Multi-framework teams — adopt incrementally.
  • Strict bundle size targets — astro pages routinely ship < 20 KB JS.

React/Next wins:

  • App-shaped products — dashboards, admins, full SPAs where most of the tree is interactive.
  • Heavy state coordination between components (cart, auth, real-time).
  • Existing React ecosystem dependencies that don’t fit islands.

The rough rule: if your page is “80% static prose, 20% interactive widgets,” islands are great. If it’s “80% interactive widgets,” React/Next.

Q: How is RSC + selective hydration similar / different?

A:

Islands (Astro) RSC + selective hydration
Static rendering build/server time server runtime (RSC)
Hydration trigger explicit directives implicit (Suspense boundaries + interaction)
Multi-framework yes (Astro) React only
Granularity per-component, per-trigger per-Suspense-boundary
Mental model “static page + sprinkled interactivity” “React app with server-only parts”
Streaming no (build/serve static) yes (streamed with Suspense)

Both achieve “minimize hydration cost.” Islands take it further by being content-first (static is the default). RSC keeps the React mental model but moves work to the server.

For a content-first site: islands. For an interactive app: RSC. For an interactive app with some content pages: hybrid (Next.js for app, separate Astro for marketing — or all Next.js with RSC).

Q: Astro’s content collections.

A: Built-in API for typed markdown/MDX content:

// src/content/config.ts
import { z, defineCollection } from "astro:content";

export const collections = {
  blog: defineCollection({
    schema: z.object({
      title: z.string(),
      date: z.coerce.date(),
      draft: z.boolean().default(false),
    }),
  }),
};
---
import { getCollection } from "astro:content";
const posts = await getCollection("blog", ({ data }) => !data.draft);
---

<ul>
  {posts.map(p => <li>{p.data.title}</li>)}
</ul>

Zod-validated, type-safe content. Way better than hand-rolled markdown parsing for a blog.

Q: Server endpoints in Astro.

A: Astro can be hybrid (some routes pre-rendered, some SSR’d) — output: "hybrid" in config. API routes work like Next.js:

// src/pages/api/posts.ts
import type { APIRoute } from "astro";

export const GET: APIRoute = async () => {
  return new Response(JSON.stringify({ posts }), {
    headers: { "Content-Type": "application/json" },
  });
};

For most content sites, you don’t need many — the static + a few endpoints model fits.

Q: How does deployment compare?

A:

  • Astro (static mode) — produces a dist/ folder, deploy to any static host (S3 + CloudFront, Vercel static, Netlify, GitHub Pages). Zero compute cost.
  • Astro (SSR mode) — needs a server runtime; deploys to Vercel, Netlify Functions, Cloudflare Pages, Deno Deploy.
  • Next.js with App Router — needs Node or Edge runtime; Vercel is the natural fit, others work.

Astro static is the cheapest possible deployment ($0 + CDN bandwidth). Next.js is more flexible but always needs compute.

Q: When did “islands” become a thing?

A: Coined by Katie Sylor-Miller / Jason Miller (Preact creator) circa 2019; popularized by Astro starting in 2021. The architecture predates the name — sites have always shipped mostly static HTML with sprinkled interactivity. The frameworks made it ergonomic.

The convergence: React’s RSC (2023+) brought a similar concept to React-land, validating the architecture. Now both ecosystems independently arrived at “minimize JS, opt into interactivity.”

Gotchas / edge cases

  • Islands can’t easily share state — each is isolated. For shared state, use a state library (Nano Stores in Astro) or postMessage between islands.
  • client:only skips SSR — the component’s HTML doesn’t pre-render. SEO sees a fallback or nothing. Use sparingly.
  • Hydration cost still real per island — many small islands = many small hydrations. For dense interactivity, the React-app model is more efficient.
  • Astro + heavy React app — Astro is content-first; if your app is mostly React with React Router, you’re using Astro as a worse Next.js.
  • Markdown processing at build — large content sites have long build times. ISR / on-demand build for new content (Astro supports SSR or hybrid mode for this).
  • CSS isolation — Astro scopes styles per component by default; works across frameworks. Don’t expect Tailwind utility classes to “just work” without explicit setup.

What a senior is expected to say

  • “Islands architecture = mostly static HTML + interactive components that hydrate independently. Astro is the leader; Fresh, Iles, Marko are alternatives.”
  • “Hydration triggers per island (client:load, client:visible, client:idle, client:media) — explicit control React’s auto-prioritization doesn’t have.”
  • “Multi-framework: Astro hosts React + Vue + Svelte + Solid in one page. Each framework’s runtime ships only when an island uses it.”
  • “Use islands for content-heavy sites (blogs, docs, marketing). Use React/Next for app-shaped products. Hybrid OK — Astro for marketing, Next for app.”
  • “RSC + selective hydration is React’s parallel-evolution answer. Different mental model (React app + server-only) vs Astro’s (static page + sprinkled interactivity).”
  • “Astro static deploys to any CDN for free; SSR mode needs compute. Content Collections + Zod is excellent for typed markdown.”

Cross-references

Further reading