Skip to content

Server Islands

Client islands are about client-side interactivity. Server islands solve a different problem: a page that is mostly cacheable and static, but has one part that is personalized or slow — the logged-in user’s avatar, a “recommended for you” strip, a live price that needs a fresh query.

Without server islands you’re forced to choose: render the whole page on demand (losing the cache on the 95% that never changes), or give up the personalized part. Server islands let you have both — cache the shell, defer the dynamic bit.

Add the server:defer directive to any .astro component to turn it into a server island. Astro then renders the rest of the page immediately — without waiting for that component — and the deferred component’s real HTML is fetched separately and swapped in when ready.

---
import Avatar from '../components/Avatar.astro';
---
<Avatar server:defer />

The page’s initial HTML ships right away and can be cached at the edge. The Avatar renders on the server — so it can safely read cookies, a session, or a database — but out of band, on its own request, after the shell is already on screen.

Because the real content arrives a moment later, you provide fallback content to show in the meantime — a skeleton, a spinner, or a generic placeholder — using slot="fallback":

---
import Avatar from '../components/Avatar.astro';
import GenericAvatar from '../components/GenericAvatar.astro';
---
<Avatar server:defer>
<GenericAvatar slot="fallback" />
</Avatar>

The GenericAvatar renders into the cached shell immediately; the personalized Avatar replaces it once its own server render returns.

flowchart TB
  req["request the page"] --> shell["server renders shell instantly (cacheable)"]
  shell --> fb["fallback shown in place of the island"]
  fb --> fetch["browser fetches the deferred island"]
  fetch --> srv["island renders on the server (cookies, session, db)"]
  srv --> swap["real HTML swapped in over the fallback"]
The page ships with a fallback, then the deferred island is fetched and swapped in

When to use them (and the adapter requirement)

Section titled “When to use them (and the adapter requirement)”

Server islands are the right tool when a page is cacheable except for a small dynamic piece:

  • A marketing or product page that’s identical for everyone except a personalized greeting or cart.
  • A mostly-static page with one slow query you don’t want blocking first paint.
  • Auth-gated fragments on an otherwise public, CDN-cached page.

Two things to remember. First, server:defer renders on the server, so it needs an adapter installed (Cloudflare, Node, Vercel…) — the same requirement as any on-demand rendering; without one you’ll hit the “an adapter is required” error. Second, it’s not for client interactivity — if the piece needs to respond to clicks, that’s a client island (a client directive), possibly in addition. Server islands are about deferring server-rendered output, not hydrating JavaScript.

What does server:defer do?
What is the main use case for a server island?
How do you show something while a server:defer component loads?
What does a server island require to run?