SSR framework for Svelte 5 + Bun with islands-based selective hydration
On this page
Installing mochi-framework puts a mochi-framework binary on your PATH. Inside a project it’s available to package.json scripts directly; anywhere else, run it with bunx:
bunx mochi-framework <command> [options]bunx mochi-framework --help # list every commandbunx mochi-framework --version # print the installed version-h/--help and -v/--version work as shorthands.
build
Produces a production bundle by reading config straight from your entry’s Mochi.serve() call, so the prebuilt manifest stays single-sourced with the runtime. This is the command behind your build script:
{
"scripts": {
"build": "mochi-framework build"
}
}| Option | Default | Description |
|---|---|---|
--entry <path> | ./src/index.ts | Runtime entry whose Mochi.serve() call supplies routes, markdown, optimize, and publicDir. |
--out-dir <path> | ./.mochi | Base build output directory. --dev builds nest under <out-dir>/dev. |
--public-dir <path> | ./public | Static assets directory. Scanned, never copied — see below. |
--asset-prefix <path> | /_mochi | URL prefix for framework client assets. |
--dev | off | Build with development: true. |
Every SSR entrypoint it compiled is listed as one tree. Your routes come first, then the three groups no route reaches: the error page renders on a throw, an email template on a send, and a server island on a fetch of its own endpoint.
Route islands bundle
┌ ● / 1 2.45 kB
├ λ /health - -
├ ● /orders/:id 1 2.45 kB
│
│ Error page
├ ⚠ $mochi/templates/DefaultError.svelte 1 3.17 kB
│
│ Email template
├ ✉ src/emails/Receipt.svelte - 316 B
├ ✉ src/emails/Welcome.svelte - 288 B
│
│ Server island
├ ◐ /_mochi/island/Cart_3iqkh56ovhduk 1 89.6 kB
└ ○ /_mochi/island/Stamp_dnp0teboqefy 0 235 B
● page with islands · λ api · ⚠ error page · ✉ email template · ◐ server island with islands · ○ server islandNotes on the three trailing groups:
- The error page is Mochi’s built-in one until you set
errorPage, which is why it reads$mochi/…above. - Email templates are found by walking
src/emails/— nothing imports one from a route, so there is no import graph leading there. Their islands column reads-because an island in a template fails the build. - Server islands are listed by the endpoint the browser fetches, not by file: the name carries a hash, and two islands can share a source file while keeping separate URLs. The prefix follows
--asset-prefix.◐marks one whose rendered HTML contains hydratable islands of its own — the same thing the islands column counts on every other row, so amochi:defer mochi:hydrateisland reads○here and is counted against the page that mounts it.
After the tree, the build lists the resources it emitted — one row per local image import, largest first, so an oversized import is obvious:
Resource dimensions size
┌ ▣ error-page-3jm1noc19vxtj.png 1400×807 330 kB
└ ▣ debug-bar-ycfe5vg1pwxv.png 1036×72 22.5 kB
2 assets · 353 kBSilence the list with Mochi.serve({ build: { resources: false } }) — the build: done summary still reports the asset count.
The manifest stores all artifact paths relative to the out-dir, so the build output is relocatable — move or copy it and boot with outDir (or manifest) pointing at the new location. See Deployment for how the output is served and Relocatable builds for the remaining constraints.
Static files are the exception: the build reads --public-dir only to reject a file that shadows one of your routes, and copies nothing. The runtime serves that directory from disk, so it travels with your source rather than with .mochi/. A 0 public file(s) in the summary for an app that has static assets means --public-dir (or the entry’s publicDir) points somewhere unexpected.
generate-key
Generates a MOCHI_KEY (a base64url-encoded 32-byte secret — the format server-island prop encryption expects) and writes it to .env in the current directory:
bunx mochi-framework generate-keyIt creates .env if missing, appends MOCHI_KEY if absent, and prompts before overwriting an existing key.
| Option | Description |
|---|---|
-f, --force | Overwrite an existing MOCHI_KEY without prompting. |
update-skill
Fetches the latest SKILL.md — agent guidance for coding assistants — and writes it into your project for the given agent (default: claude-code):
bunx mochi-framework update-skill [agent]Run it again whenever you upgrade the framework to keep the guidance in sync. The optional agent argument controls the destination; see Docs for LLMs for the full list of supported agents.