Server Islands
Server islands let you render expensive or dynamic components on the server without blocking the initial page shell. The page loads instantly with a placeholder, then the island streams in when the server-side data is ready.
Different from
"use client"and"use signals"islands. Server islands are about deferred server rendering — the component still runs on the server, just streamed late so the shell ships first. For interactive islands that hydrate in the browser, see"use client"(React-based) or"use signals"(no React, ~3 KB).
How It Works
Mark a component as a server island with the island directive:
// components/ProductReviews.tsx
"use island";
export default async function ProductReviews({ productId }: { productId: string }) {
// This fetch happens on the server, after the page shell is sent
const reviews = await db.reviews.findMany({ where: { productId } });
return (
<section>
<h3>{reviews.length} Reviews</h3>
{reviews.map((r) => (
<div key={r.id}>
<strong>{r.author}</strong>
<p>{r.body}</p>
</div>
))}
</section>
);
}
// pages/product/[id].tsx
export default function ProductPage({ params }: { params: { id: string } }) {
return (
<main>
<h1>Product Details</h1>
<p>This part renders immediately.</p>
{/* This streams in after the data fetch completes */}
</main>
);
}
Rendering Behavior
1. Page shell — bext renders the full page, replacing islands with a <bext-island> placeholder element
2. Streaming — each island renders in parallel on the server via the V8 pool
3. Injection — completed islands stream into the page as <script> tags that replace their placeholder
4. Hydration — if the island has client-side interactivity, React hydrates it after injection
This means:
- Time to first byte is fast because the shell doesn't wait for slow data
- Islands render in parallel, not sequentially — a slow database query in one island doesn't block others
- SEO is preserved — the final HTML contains the full rendered content for crawlers
Configuration
# bext.config.toml
[render]
islands = true # default: auto-detected from "use island" directives
island_timeout_ms = 10000 # timeout per island (renders fallback on timeout)
island_concurrency = 8 # max parallel island renders per request
Fallback Content
Provide a fallback that shows while the island is loading or if it times out:
Loading reviews...</p>} />
If the island fails or times out, the fallback stays in place and an error is logged. The rest of the page is unaffected.
When to Use Server Islands
| Use case | Recommendation |
|---|---|
| Personalized content (cart, user profile) | Server island — avoids caching issues |
| Slow database queries | Server island — doesn't block the page shell |
| Static content | Regular SSR — no need to defer |
| Real-time data | Combine with SSE via the real-time hub |
| Below-the-fold content | Server island — improves perceived performance |
Comparison with Streaming SSR
Server islands differ from React's built-in `` streaming:
- Islands are component-level — you mark individual components, not Suspense boundaries
- Islands run in parallel — the V8 pool distributes renders across workers
- Islands support timeout + fallback — graceful degradation is built in
- Islands work without React — they're a bext platform feature, not tied to a framework