A folder with frontend: { stack: "svelte" }. Pages are .svelte, layouts are layout.svelte. Routing, fetch clients and validation behave the same for every frontend. Frontend intro ›
Module exports need <script module>
This is the Svelte-specific trap. loader and staticParams are module exports, so they belong in <script module> - the instance <script> runs per component and cannot declare them:
<!-- Svelte: pages/users/[id]/index.svelte -->
<script module lang="ts">
import fetchClients from "_/fetch";
const { GET } = fetchClients["users/[id]"];
export const loader = ({ params }) => GET([params.id]);
</script>
<script lang="ts">
import { useLoaderData } from "_/use";
const user = useLoaderData();
</script>
{#if user}
<h1>{user.name}</h1>
{/if}The router runs the loader before render, so the data is there on first paint.
Hooks
_/use exists in Svelte folders and is the full set - useLoaderData, useRoute, useParams, useParamsEntries, useSearchParams. There is no third-party router to import from.
Hooks must be called at the top level of a <script> block, never inside a function or at module scope:
<script lang="ts">
import { useParams } from "_/use";
const { id } = useParams<"users/[id]">(); // top level
</script>useLoaderData() returns T | undefined. A layout passes its path-qualified name - useLoaderData("dashboard/layout") - where a page passes nothing. A loader cannot use hooks; it receives the resolved route object instead.
Layouts
<!-- Svelte: layout.svelte -->
<script lang="ts">
let { children } = $props();
</script>
<div class="dashboard">
<nav>...</nav>
<main>
{@render children()}
</main>
<footer>...</footer>
</div>Child routes arrive as the children snippet and render with {@render children()}.
Worth knowing
- SSR is string-only.
renderMode: "stream"is not available for Svelte folders; React, SolidJS and Vue can stream. - Svelte has no third-party router, so KosmoJS supplies the matcher and emits its own
RawRouteshape rather than a framework route tree. Routing › - TanStack Query names its hooks
createQuery/createMutation, notuse*, and they take a thunk.