SSR framework for Svelte 5 + Bun with islands-based selective hydration
On this page
Hydratable values (experimental)
hydratable support is experimental, please create an issue if you find problems! 🙇
Svelte 5’s hydratable(key, fn) computes a value on the server, serializes it into <head>, and reads it back during client hydration instead of recomputing. Use it to avoid running the same async work twice when a hydrated component does data fetching at the top level.
Without it, the function runs once on the server and again during hydration:
<script>
import { getUser } from 'my-database-library';
// Runs on the server AND again on the client during hydration.
const user = await getUser();
</script>
<h1>{user.name}</h1>With it, the server result is reused on the client:
<script>
import { hydratable } from 'svelte';
import { getUser } from 'my-database-library';
// SSR: runs `getUser`, devalue-serializes the result into <head>.
// Client: reads the value from window.__svelte.h, never invokes `getUser`.
const user = await hydratable('app:user', () => getUser());
</script>
<h1>{user.name}</h1>Mochi already wires this up: any hydratable() call inside a Mochi.page(...) route or a mochi:hydrate* island is collected into the page’s head script during SSR and picked up by Svelte’s hydrate() automatically. There’s no extra Mochi-side import — hydratable comes straight from svelte.
See it in action in the Hydratable demo, where the page and a hydrated island share the same key — the server function runs once, both sides render the same value, and the island skips the async work on hydration.
Serialization
Values are serialized with devalue, so Map, Set, Date, URL, BigInt, and circular references all round-trip. Promises also work — Svelte stitches them back together on the client.