SvelteKit on onvibe Three approaches are available depending on whether you need SSR and how you want to manage the build output. > Important — onvibe has NO install or build phase. It does not run npm install or > npm run build for you; it just serves the files you deploy. So every npm … command below > runs in your own local environment (a machine with Node/npm). You build there, then upload > only the build output with stage_files + deploy. Runtime npm dependencies still work via > Deno's npm: specifier (e.g. import { Pool } from "npm:pg") — that needs no install step. If > your assistant has no local shell to run the build (many MCP clients don't), prefer a plain > Deno/TypeScript app or the web/api templates instead of a SvelteKit build. --- Option A — SSR with @deno/svelte-adapter (recommended for SSR) Real server-side rendering on every request. 1. Install and configure npm install -D @deno/svelte-adapter // svelte.config.js import adapter from "@deno/svelte-adapter"; export default { kit: { adapter: adapter({ out: "output" }) } }; npm run build Outputs to: output/server/ and output/client/ 2. Write main.ts wrapper The adapter's output cannot be used directly — write a main.ts that imports the server bundle and exports a default handler: import { Server } from "./output/server/index.js"; import { manifest } from "./output/server/manifest.js"; const mimeTypes: Record = { ".js": "application/javascript", ".css": "text/css", ".html": "text/html; charset=utf-8", ".png": "image/png", ".jpg": "image/jpeg", ".svg": "image/svg+xml", ".ico": "image/x-icon", ".woff2": "font/woff2", ".json": "application/json", }; function mime(path: string): string { const ext = path.slice(path.lastIndexOf(".")); return mimeTypes[ext] ?? "application/octet-stream"; } const server = new Server(manifest); await server.init({ env: Deno.env.toObject() }); export default async function handler(req: Request): Promise { const url = new URL(req.url); // Serve static assets from disk (output/client/) try { const file = await Deno.open(./output/client${url.pathname}); const stat = await file.stat(); if (!stat.isDirectory) { const immutable = url.pathname.startsWith("/_app/immutable/"); return new Response(file.readable, { headers: { "content-type": mime(url.pathname), "cache-control": immutable ? "public, max-age=31536000, immutable" : "no-cache", }, }); } file.close(); } catch { // Not a static file — fall through to SSR } return server.respond(req, { getClientAddress: () => req.headers.get("x-forwarded-for") ?? "", platform: {}, }); } 3. Deploy in chunks The build output typically has 30–50 files. Use stage_files: stage_files("my-app", [main.ts, output/server/index.js, ...chunk1]) stage_files("my-app", [output/client/_app/..., ...chunk2]) stage_files("my-app", [...remaining files]) deploy("my-app") See onvibe://docs/large-deploy for the full chunked deploy workflow. --- Option B — adapter-static (pre-rendered, no SSR) Use when the app has no dynamic server-side logic. Simpler: the entire build fits in a single main.ts with pages and assets embedded as strings. // svelte.config.js import adapter from "@sveltejs/adapter-static"; export default { kit: { adapter: adapter() } }; // main.ts — embed build output as strings const pages = new Map([ ["/", "..."], ["/about", "..."], ]); const assets = new Map([ ["/_app/immutable/entry/start.js", "// bundled js"], ]); export default async function handler(req: Request): Promise { const path = new URL(req.url).pathname; const asset = assets.get(path); if (asset) return new Response(asset, { headers: { "content-type": "application/javascript", "cache-control": "public, max-age=31536000, immutable" } }); const page = pages.get(path) ?? pages.get("/"); return new Response(page ?? "Not found", { status: page ? 200 : 404, headers: { "content-type": "text/html; charset=utf-8" } }); } --- Option C — adapter-cloudflare (CF Workers export shape) Use when you want to target the CF Workers runtime format. The platform runs the CF Workers module natively and provides an ASSETS shim for serving static files from disk. 1. Install and configure npm install -D @sveltejs/adapter-cloudflare // svelte.config.js import adapter from "@sveltejs/adapter-cloudflare"; export default { kit: { adapter: adapter() } }; npm run build Outputs to: .svelte-kit/cloudflare/ Main bundle: _worker.js Static assets: _app/, favicon.png, etc. 2. Write main.ts wrapper Re-export the worker module as the default export: // main.ts export { default } from "./_worker.js"; The platform detects the CF Workers module shape (export default { fetch }) and provides: - env.ASSETS — serves static files from the deployed file tree 3. Deploy in chunks stage_files("my-app", [main.ts, _worker.js]) stage_files("my-app", [_app/immutable/..., favicon.png, ...]) deploy("my-app") Notes - API routes (+server.ts) work if your SvelteKit build includes them in _worker.js - Database connections: use Deno.env.get("DATABASE_URL") — it is injected automatically and accessible from within _worker.js via the standard env object - SSR: supported if your SvelteKit config enables it (no "export const prerender = true" on all pages) --- Which to choose Option A (@deno/svelte-adapter) Option B (adapter-static) Option C (adapter-cloudflare) SSR per request ✅ ❌ ✅ API routes (+server.ts) ✅ ❌ ✅ $state / reactivity ✅ ✅ (client only) ✅ File count 30–50 files 1 file 10–30 files Deployment stage_files + deploy deploy directly stage_files + deploy Build target Deno-native static HTML CF Workers