🍡 mochi

SSR framework for Svelte 5 + Bun with islands-based selective hydration

On this page

Hydratable values (experimental)

hydratable support is experimental. Please open an issue if you find problems.

Svelte 5’s hydratable(key, fn) computes a value on the server, serializes it into the page, and reads it back during client hydration. Use it to avoid running the same async work twice when a hydrated component fetches data at the top level.

Without it, the function runs 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 client reuses the server result:

<script>
  import { hydratable } from 'svelte';
  import { getUser } from 'my-database-library';

  // SSR: runs getUser and serializes the result into the page.
  // Client: reads the serialized value and skips getUser.
  const user = await hydratable('app:user', () => getUser());
</script>

<h1>{user.name}</h1>

Mochi wires this up. Any hydratable() call inside a Mochi.page(...) route or a mochi:hydrate* island is collected during SSR and picked up by Svelte’s hydrate() automatically. Import hydratable straight from svelte.

Serialization

Mochi serializes values with devalue, so Map, Set, Date, URL, BigInt, and circular references round-trip. Promises work too — Svelte stitches them back together on the client.

Limitations in Mochi today

See it in action

Live demos showing key concepts from this page