← Writing
The Editorial · Engineering

Islands architecture — or why your blog post is shipping a whole app to read three thousand words

Issue 026Aug 6, 202610 min read

You open an article on your phone. The words are there in a second. You tap the menu and nothing happens for another three. The page was finished — it just wasn't awake yet, because your phone was busy rebuilding, from scratch, the same page the server had already built and sent you. Islands architecture is the idea that a page mostly made of text should be sent as text, with a few small powered zones for the parts that actually respond to a tap. Here's what that means, where it pays, and where it's exactly the wrong shape.

The issue

You open a news article on your phone, on ordinary mobile data. The headline and the first paragraphs are there almost immediately — good, fast, nothing to complain about. Then you tap the menu. Nothing. You tap it again, slightly harder, the way everybody does. Two or three seconds later the menu opens, and possibly the page jumps because something else finished loading underneath your thumb.

The page was finished. You could read every word of it. It just wasn't awake yet, and the reason why is the single strangest thing about how modern websites are built — strange enough that it's worth explaining properly even if you never write a line of code.

The page gets built twice

A server somewhere ran your app, produced a finished HTML page, and sent it to your phone. That's why the words appeared quickly. But the buttons in that HTML aren't connected to anything — HTML is paper. So the site then sends your phone all the JavaScript that would have built that page, and your phone downloads it, parses it, and runs the whole thing again, on top of the page that's already there, purely to work out which handler belongs to which button.

That second build has a name — hydration — and it happens on the slowest computer in the entire chain. Not the server. Not your laptop. Somebody's four-year-old Android, on a train, on 4G. The gap you felt when you tapped the menu is that.

what happens between "the page appeared" and "the page works"looks finishedactually worksHTMLdownload JSparse + runreadyyou can see it — you cannot use it yetserver builds ityour phone builds it againthat second build is what "hydration" means
Fig 1The words arrive early and the page looks done. Nothing responds until the browser has finished rebuilding it.AI-generated figure

And the crucial detail: hydration is all or nothing. The page is one component tree, so the browser walks the whole tree top to bottom. There's no way to say "do the menu first, the comments never." It's one pass, and it costs what it costs.

The observation

So here's the question islands architecture asks, and once you've heard it you can't stop applying it to every site you open: how much of this page actually responds to a tap?

On a news article — the menu toggle, the like and share row, the comment box, maybe an embedded video. That's it. The headline is text. The byline is text. Three thousand words are text. The images are images. The related-articles list at the bottom is five links. None of it will ever respond to anything, and all of it got rebuilt anyway, because it was in the tree.

a news article, coloured by what responds to a tapmenu togglelike + sharecomments3,000 words of textrelated articlesroughly 5% of the page — and 100% of the JavaScript bill
Fig 2Colour a content page by what genuinely needs JavaScript and almost all of it goes grey — but the grey part is what you were paying for.AI-generated figure

The name comes from that picture. The interactive bits are islands in a sea of static HTML. Send the sea as HTML — it's already correct, it needs nothing — and give each island only the code it needs.

What that looks like

Astro is the reference implementation, and the syntax is almost embarrassingly direct. You mark a component with when it should come alive, and everything you don't mark is simply HTML forever.

src/pages/blog/[slug].astroAstro
---
import LikeButton from "../../components/LikeButton.jsx";
import Comments from "../../components/Comments.jsx";
import RelatedPosts from "../../components/RelatedPosts.astro";
const post = await getPost(Astro.params.slug);
---

<article>
  <h1>{post.title}</h1>
  <Fragment set:html={post.html} />
</article>

<LikeButton client:load count={post.likes} />
<Comments   client:visible postId={post.id} />
<RelatedPosts posts={post.related} />
when each part of the page wakes upclassic SSR — one hydration passthe entire page, before anything is clickableislands — three separate wake-upsclient:loadon loadclient:idlewhen idleclient:visibleon scrollpage arriveslatermost readers never reach the comments, so most never download them
Fig 3Instead of one pass over everything, three small ones that each start when there's a reason to.AI-generated figure

The best real-world comparison for client:visible is the escalator at a metro station that idles until someone steps on the plate. You don't run every escalator in the building all day for the handful of people who'll use them in the next hour. You start each one when somebody arrives.

Three things follow from the model that are worth knowing even secondhand. Each island is its own root — two islands on the same page don't share a component tree or a state store unless you deliberately wire one up. They hydrate in parallel and independently, not in one top-down sweep, so a heavy island can't hold up a light one. And the HTML is the real thing, not a preview of the real thing — which is why this shape is quietly excellent for search engines and screen readers, for the same reasons Issue 021 goes into.

The one that saves your CDN bill

There's a newer half of this worth knowing about, because it fixes a problem almost every product hits. You have a product page that is identical for everyone — the photos, the description, the price, the reviews — except for one small box in the corner that says "recommended for you" or shows the logged-in user's avatar. That one box means the page is different for every visitor, which means the CDN can't cache it, which means every single view goes all the way back to your server. One widget, and you're paying to render a page that hasn't meaningfully changed in three weeks.

server-islands.astroAstro
<!-- the page is now cacheable again; these two fill in after -->
<Avatar server:defer>
  <GenericAvatar slot="fallback" />
</Avatar>

<Recommendations server:defer userId={Astro.cookies.get("uid")}>
  <p slot="fallback">Picking something out for you…</p>
</Recommendations>
one personalised box, two ways to serve the pageno server islandsthe entire page rendered fresh for every visitorthe CDN cannot cache any of it, because one box is differentwith server:defercached HTML, straight from the CDNjust thisone small hole filled per user — the other 95% is a cache hitthe same idea as islands, moved one step back to the server
Fig 4Server islands apply the same carving to the server side: cache the 95% that's identical, defer the small piece that isn't.AI-generated figure

Same idea, moved one step back. Islands split the page by what needs JavaScript; server islands split it by what's different per person. Both are just refusing to let a small special case set the price for the whole page.

If you don't write the code

This is the pattern with the clearest commercial edge of any in this series, and it has almost nothing to do with elegance.

Your marketing site, your pricing page, your blog, your docs and your changelog are the pages a stranger judges you on and the pages Google reads first. They are also the pages with essentially no interactivity. If they were built with the product's stack because "we already use React and it's one repo," you are paying application performance costs on your acquisition funnel — and the people who feel it hardest are exactly the ones on cheap phones and patchy networks that you were hoping to convert. A documentation site built on islands typically ships something like 80% less JavaScript than the same site built as an app. That is not a micro-optimisation; that's a different product on a mid-range phone.

The right question in that meeting isn't which framework. It's "what percentage of this page actually responds to a click?" Under ten percent, islands. Over half, don't — and knowing which of your pages is which is a five-minute conversation that saves a quarter of arguing.

When it's the wrong shape entirely

Islands are genuinely bad at some things, and the failure isn't subtle — it's the kind where you notice in week two and it never gets better.

It's also worth knowing that islands aren't the only answer to this complaint. React Server Components keep the single tree and move work to the server instead of abandoning the tree. Qwik skips hydration altogether by recording which handler belongs to which element and fetching it on the first click. Three different answers to the same observation — that most pages ship far more JavaScript than they use — and which one fits depends entirely on how much of your page moves.

For the framework-by-framework detail — Astro's directives in full, Fresh, Marko, and where Server Islands landed — patterns.dev's Islands Architecture writeup is the right next stop. If you want the measuring side of this before you change anything, Issue 019 is the one about finding out where the time actually goes.

All issues