Skip to content
Back to the Lab
Frontend Architecture

Islands Architecture for Modern Web Applications

A complete guide to islands architecture for frontend developers. Covers partial hydration, server rendered HTML, resumability, and how frameworks such as Astro and Qwik reduce JavaScript payloads while keeping pages fast and interactive.

Islands Architecture for Modern Web Applications

Introduction#

For most of the last decade, the dominant approach to building web interfaces was the single page application. A browser downloads one large JavaScript bundle, that bundle takes over the entire page, and every pixel on screen is rendered and controlled by client side JavaScript. This model gave developers a powerful and consistent programming model, but it came with a cost that became harder to ignore as applications grew larger: users had to download, parse, and execute an entire application runtime before they could see or touch anything meaningful on the page.

Islands architecture is a direct response to that cost. Instead of treating a page as one large application that must be hydrated in full before it becomes interactive, islands architecture treats a page as mostly static HTML with small, independent pockets of interactivity placed across it. Each pocket, commonly called an island, ships and hydrates its own JavaScript, separate from every other part of the page. The static regions surrounding it never load a script at all.

The term was coined by Etsy frontend architect Katie Sylor Miller in 2019 and later expanded into a widely referenced article by Preact creator Jason Miller in 2020. Since then it has moved from a niche idea into a mainstream pattern, supported natively by frameworks such as Astro, Fresh, Marko, Qwik, and Enhance. In 2026, with Core Web Vitals tied directly to search visibility and a large share of traffic still arriving on mid range mobile devices, islands architecture is one of the clearest paths available to teams that want fast, content heavy pages without giving up interactivity where it genuinely matters.

What Islands Architecture Actually Means#

At its core, islands architecture separates a page into two categories of content.

The first category is static HTML. This includes headers, footers, article text, navigation, and any other content that does not respond to user interaction. This HTML is produced on the server or at build time and shipped to the browser exactly as is. No JavaScript is attached to it, and none is downloaded on its behalf.

The second category is islands. An island is a self contained interactive component, such as an image carousel, a comment form, a shopping cart widget, or a search box. Each island is rendered to HTML on the server just like the content around it, but it also ships a small script that hydrates that specific region of the DOM once the browser reaches it. Islands are isolated from one another by design, so a slow or failing island does not block the rest of the page from becoming usable.

This is fundamentally different from the hydration model used by most single page application frameworks, where the entire page is treated as one component tree that must be hydrated together before any part of it responds to user input.

How Partial Hydration Works Under the Hood#

The technique that islands architecture builds on is often called partial hydration, or selective hydration. Rather than hydrating every component the moment the page loads, a partial hydration system lets each island declare when it should hydrate.

Common strategies include hydrating as soon as the page loads, hydrating only once an island scrolls into the viewport, hydrating during a browser idle period, or hydrating only when a particular media query matches. A framework like Astro expresses this directly in the markup through client directives.

<Counter client:load />
<SearchBox client:idle />
<Newsletter client:visible />
<MobileMenu client:media="(max-width: 768px)" />

Each directive tells the framework exactly when to fetch and execute that island’s JavaScript. A newsletter form far down the page has no reason to hydrate before a user has scrolled anywhere near it, and a mobile menu has no reason to hydrate at all on a desktop viewport. This granularity is the mechanism that keeps the total amount of JavaScript executed on initial load as small as possible.

Comparing Islands Architecture and Traditional Hydration#

In a typical single page application, the framework treats the whole page as a single dependency graph. Even if only a search box needs interactivity, the framework still has to construct and hydrate the component tree for the header, the footer, and every static section in between, because they are all part of the same tree.

Islands architecture removes that requirement entirely. Each island is hydrated independently, with its own isolated component tree, its own bundle, and its own lifecycle. This has a second benefit beyond raw performance: blast radius. If one island throws an error during hydration, it does not take down the rest of the page. The static content keeps working, and other islands continue to hydrate normally.

It is worth placing islands architecture alongside two related but distinct ideas that also address the cost of hydration. React Server Components move rendering work to the server and only ship client bundles for components explicitly marked as interactive, which shares the same underlying goal as islands even though the implementation differs. Qwik takes a more radical approach called resumability, where the framework serializes application state directly into the HTML and resumes execution from that point without replaying any component tree on the client at all, effectively removing the hydration step altogether rather than just narrowing it.

Implementing a Simple Island Loader#

Understanding the mechanism behind islands architecture is easier by building a minimal version of it. The following example scans the DOM for elements marked as islands and hydrates each one only once it enters the viewport, using the Intersection Observer API.

const islands = document.querySelectorAll("[data-island]");

const observer = new IntersectionObserver(async (entries) => {
  for (const entry of entries) {
    if (!entry.isIntersecting) continue;

    const name = entry.target.getAttribute("data-island");
    const module = await import(`./islands/${name}.js`);
    module.hydrate(entry.target);

    observer.unobserve(entry.target);
  }
});

islands.forEach((element) => observer.observe(element));

Every element carries a data attribute naming the component it represents. Nothing is imported or executed until that specific element becomes visible, which means a long article with several widgets far down the page pays almost no JavaScript cost on initial load. This is the same principle full frameworks like Astro implement, just expressed at a smaller scale.

Common Pitfalls When Adopting Islands Architecture#

Teams moving to this pattern tend to run into a few recurring issues.

Splitting a page into too many tiny islands can backfire. Each island typically means a separate network request and a separate bundle, and the overhead of many small requests can offset the savings gained from avoiding one large bundle. Grouping closely related interactive elements into a single island is often more efficient than isolating every individual button.

Sharing state across islands also requires deliberate design. Because islands are isolated by default, there is no shared component tree or context provider connecting them the way there would be in a typical single page application. Teams usually reach for a lightweight shared store, custom browser events, or URL state to coordinate behavior between islands that need to communicate.

Finally, adopting this pattern inside an existing large single page application is rarely a simple configuration change. It often requires restructuring how pages are composed, since the underlying assumption, that the whole page is one component tree, is different from the assumption islands architecture is built on.

Islands Architecture and Search Visibility#

Because the majority of a page’s content is already rendered as HTML rather than assembled by client side JavaScript after load, search crawlers see the full content immediately without needing to execute a script first. This has a direct effect on both indexing reliability and Core Web Vitals, particularly Largest Contentful Paint and Interaction to Next Paint, since the main thread is never occupied hydrating a large component tree that the user may not even need yet.

For content heavy sites such as blogs, documentation, marketing pages, and online stores with a handful of interactive widgets, this combination of fast rendering and minimal JavaScript tends to translate directly into stronger performance scores and more reliable search visibility.

When Islands Architecture Is the Right Choice#

This pattern fits naturally with content heavy products where most of the page is read only and only a few regions need interactivity. It is a poor fit for applications where nearly everything on screen is interactive at once, such as a design tool, a spreadsheet, or a real time dashboard, where a component based single page application or a resumable framework is likely to be a better foundation.

Conclusion#

As browsers and users continue to punish heavy JavaScript payloads, islands architecture, alongside related ideas such as server components and resumability, reflects a broader shift in frontend thinking. The goal is no longer shipping a full application runtime to every visitor by default. It is shipping only what a given page actually needs. Frontend teams building content driven products in 2026 have more mature tooling than ever to adopt this pattern without building the underlying mechanism from scratch.

References#

Astro Docs: Islands Architecture

Patterns.dev: Islands Architecture

Jason Miller: Islands Architecture

Awesome Islands: A Curated List on Islands Architecture and Partial Hydration

OpenReplay Blog: Astro Islands Architecture Explained