Reference
Performance
Client JS, Lighthouse, CLS/LCP and JS evaluation measured against SvelteKit, Astro and Mochi on identical pages.
This page compares ogygia, an islands library for SvelteKit, with other frameworks on the same pages. You can reproduce every measurement from the repository under bench/.
The benchmark
The same blog post (the same prose, the same five interactive widgets and the same CSS) is built four ways, and we measure how much client JavaScript each version ships as the post gets longer. Islands ship JS only for the widgets, so their payload stays flat, while whole-page hydration ships JS for the entire document, so its payload grows with the content.
The method is a port of the interactive-blogs-benchmark by Stanislav Khromov, with full credit to @khromov. We run it on the latest version of each tool, with ogygia added.
Mobile Lighthouse, simulated throttling. Sizes are brotli/raw of all JS the page loads. Method
ported from khromov/interactive-blogs-benchmark. Reproduce: pnpm run e2e is separate; see bench/.
Reading it
- Islands stay flat. ogygia, Astro and Mochi ship the same amount of JS whether the post is 9k or 71k words, while SvelteKit’s whole-page hydration climbs with the prose.
- ogygia compared with the other island frameworks. All of them ship Svelte 5 islands, so this compares architecture alone, with no framework handicap. Astro’s island runtime is the smallest, followed by Mochi and then ogygia. ogygia carries a somewhat larger baseline runtime in exchange for a much larger feature set: server islands, held, live and frozen regions, and full SvelteKit integration (see the matrix below).
- The runtime is feature-selected. ogygia ships only the features your app uses, so a
load-only page never pays for the router, lakes or persistence. The runtime size for each profile is tracked
in
apps/palaestra/e2e/bundle-size.snapshot.json, so it can only shrink over time.
What you can build
On payload alone, the island frameworks end up close to each other, so the bigger difference between them is what each lets you build:
| Capability | SvelteKit | Astro | Mochi | ogygia |
|---|---|---|---|---|
| SSR / prerender | ✅ | ✅ | ✅ | ✅ |
| Partial hydration (islands) | ❌ whole-page | ✅ | ✅ | ✅ |
| Client JS flat as content grows | ❌ | ✅ | ✅ | ✅ |
| Islands are Svelte 5 | ✅ | ✅ (any framework) | ✅ | ✅ |
Per-component wake: load·idle·visible·interaction·media | ❌ | ➖ (no interaction) | ? | ✅ |
| Server islands (defer render to an endpoint) | ✅ | ✅ | ? | ✅ |
Held regions: region() values you place like data | ❌ | ❌ | ❌ | ✅ |
| Frozen regions (lakes): zero-JS interactive-context subtrees | ❌ | ❌ | ❌ | ✅ |
| Live / streaming regions | ❌ | ❌ | ? | ✅ |
Built on SvelteKit: its adapters, hooks, $app, remote functions | ✅ | ❌ own framework | ❌ own framework | ✅ |
| Opt-in SPA router | ✅ | ➖ (MPA + view transitions) | ? | ✅ |
| Markdown content collections built in | ➖ add mdsvex | ✅ | ✅ | ✅ |
| Feature-selected runtime (ship only what the app uses) | — | — | ❌ | ✅ |
? means not verified for the benchmarked version. The trade-off is that ogygia carries a somewhat larger baseline runtime (see the size figures above) in return for the bottom third of this matrix, the region primitives and the Kit-native integration that none of the other frameworks here offer.
Reproduce it
# hermetic (Docker): builds every framework + runs Lighthouse
docker compose -f bench/docker-compose.yml up --build
# isolated runtime size per feature profile (rolldown, brotli)
pnpm run bundle-sizeThe numbers on this page are regenerated from bench/results/latest.json, the exact JSON the
benchmark emits.