Nested Island Max Depth
Server islands can nest to any depth, and by default Mochi inlines nested mochi:defer islands into their parent's fetch: one request returns the whole four-level chain, rendered in a single server pass. Opt out per call site with mochi:defer={{ inline: false }} to keep each level on its own fetch — its HTML then arrives with a placeholder that fetches the next level in turn, useful when a slow child shouldn't delay the parent's content. The flag is threaded down every level here, since an opt-out only applies to the call site it's written on. Either way the prebuild precompiles every level into the manifest in a single pass, so no level compiles on a request path in production.
Each level is delayed on purpose — and twice as long in the opted-out chain, so the loading pattern is easy to follow. The opted-out chain fetches level by level; the inlined chain makes one fetch that takes roughly the sum of its delays.
Opted out — waterfall {{ inline: false }}
Inlined — one fetch {{ inline: true }}
Failure modes
A child that throws during its inline attempt degrades to a placeholder and fetches on its own — the parent's content is never lost. AlwaysThrows fails its fetch too and renders the failure stub; ThrowsWhenInlined only throws while being inlined, so its own fetch succeeds and the content still arrives.
<script>
import DepthLevel1 from './DepthLevel1.svelte';
import FailDeep from './FailDeep.svelte';
import { files } from './files.ts';
const sources = await loadSources(files);
</script>
<p class="delay-note">
Each level is delayed on purpose — and twice as long in the opted-out chain, so the loading pattern is easy to follow. The opted-out chain fetches level by level; the inlined
chain makes one fetch that takes roughly the sum of its delays.
</p>
<div class="chains">
<section>
<h3>Opted out — waterfall <code>{'{{ inline: false }}'}</code></h3>
<DepthLevel1 mochi:defer={{ inline: false }} inline={false}>
<div class="island-loading">Loading level 1<span class="dots"></span></div>
</DepthLevel1>
</section>
<section>
<h3>Inlined — one fetch <code>{'{{ inline: true }}'}</code></h3>
<DepthLevel1 mochi:defer={{ inline: true }} inline={true}>
<div class="island-loading">Loading levels 1–4<span class="dots"></span></div>
</DepthLevel1>
</section>
</div>
<section class="failures">
<h3>Failure modes</h3>
<p class="delay-note">
A child that throws during its inline attempt degrades to a placeholder and fetches on its own — the parent's content is never lost. AlwaysThrows fails its fetch too and
renders the failure stub; ThrowsWhenInlined only throws while being inlined, so its own fetch succeeds and the content still arrives.
</p>
<FailDeep mochi:defer>
<div class="island-loading">Loading FailDeep<span class="dots"></span></div>
</FailDeep>
</section>
Styles
<style>
.delay-note {
margin-bottom: 0.75rem;
color: var(--text-subtle);
font-size: 0.9rem;
}
.chains {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1rem;
align-items: start;
}
.failures {
margin-top: 1.25rem;
}
.chains h3,
.failures h3 {
margin: 0 0 0.6rem;
font-size: 1rem;
}
.chains code {
font-family: var(--font-mono);
font-size: 0.85em;
color: var(--text-subtle);
}
.island-loading {
padding: 1rem;
border: 2px dashed var(--border-strong);
border-radius: var(--radius-md);
background: var(--surface-muted);
color: var(--text-subtle);
font-style: italic;
text-align: center;
}
.dots::after {
content: '';
display: inline-block;
width: 1.5em;
text-align: left;
animation: dots 1.2s steps(4, end) infinite;
}
@keyframes dots {
0% {
content: '';
}
25% {
content: '.';
}
50% {
content: '..';
}
75% {
content: '...';
}
}
</style>
More demos