SvelteKit Differences
What's the same, what's different, and what's not supported compared to SvelteKit.
Bosia follows SvelteKit conventions closely, but there are important differences.
Same as SvelteKit
These work the same way you'd expect:
- File conventions —
+page.svelte,+layout.svelte,+page.server.ts,+layout.server.ts,+server.ts,+error.svelte - Route groups —
(name)directories invisible in URLs - Dynamic routes —
[param]and[...rest]segments load()function — same signature withparams,url,locals,cookies,parent()Handletype —({ event, resolve }) => Responsesequence()— compose middleware handlers- Form actions —
actionsexport withfail()andredirect() - Cookie API —
get(),getAll(),set(),delete() $libalias — maps tosrc/lib/- CSRF protection — origin-based checking on non-safe methods
- Data invalidation —
depends()onLoadEvent, plusinvalidate()/invalidateAll()exported frombosia/client - Navigation API —
goto(),beforeNavigate(),afterNavigate()frombosia/client - Plugin system —
bosia.config.tswith hooks for backend, build, render, and client lifecycle
Different from SvelteKit
| Feature | SvelteKit | Bosia |
|---|---|---|
| Runtime | Node.js | Bun |
| Bundler | Vite | Bun.build |
| HTTP server | Configurable via adapters | ElysiaJS (built-in) |
| Adapters | Required (node, vercel, etc.) | None — single Bun server |
| Universal load | +page.ts / +layout.ts |
Not supported — server loaders only |
| Stores | $app/stores |
Not available — use $props() |
| Env vars | $env/static/public, etc. |
$env with four-tier prefix |
| HMR | Vite HMR (granular) | SSE full-page reload |
| Generated dir | .svelte-kit/ |
.bosia/ |
| Component registry | None | bosia add (shadcn-style) |
| Feature scaffolding | None | bosia feat |
| Metadata | Via <svelte:head> |
metadata() function in +page.server.ts |
| Response caching | Not built-in | Server-side cache with LRU + brotli/gzip |
data prop |
Layout data merged into pages | Each load is separate — thread via parent() |
| Loading skeletons | Manual (navigating store) |
+loading.svelte file convention (Next.js-style) |
Key Differences Explained
No universal load functions — Bosia only supports server-side load() in +page.server.ts and +layout.server.ts. There is no +page.ts or +layout.ts for client-side or universal loading.
No $app/stores — Instead of stores, access data via Svelte 5 runes:
<!-- SvelteKit -->
<script>
import { page } from "$app/stores";
</script>
<!-- Bosia -->
<script>
let { data } = $props();
</script>Layout data is not merged into the page data prop — In SvelteKit, a +page.svelte's data is the union of every ancestor +layout load plus the page's own. In Bosia each load result stays separate: a page's data holds only that page's load() return, and each layout component gets its own. So data.session (or any key a parent layout returned) is undefined in a page unless the page's own loader re-returned it. Thread parent data explicitly via parent() in the page loader — see Server Loaders. This avoids key collisions and per-page payload bloat at the cost of one extra line per page that needs ancestor data.
metadata() function — Unique to Bosia. Returns title, description, and meta tags. Can pass data to load() to avoid duplicate database queries.
$env — Instead of SvelteKit's four separate $env/* sub-modules, Bosia uses a single $env module with a prefix-based system:
// SvelteKit
import { PUBLIC_KEY } from "$env/static/public";
import { SECRET } from "$env/static/private";
// Bosia
import { PUBLIC_STATIC_KEY, SECRET } from "$env";Not Supported
These SvelteKit features are not available in Bosia:
+page.ts/+layout.ts(universal load functions)$app/stores(page,navigating,updated)- Image optimization (
@sveltejs/enhanced-img) - Service workers
- Snapshots
- Shallow routing (
pushState/replaceState) - Adapter system (tied to Bun + ElysiaJS)
<svelte:head>for metadata (usemetadata()instead)