Routing

SvelteKit uses filesystem-based routing. Files in src/routes/ map to URL paths.

Basic Routes

src/routes/
├── +page.svelte          # /
├── about/
│   └── +page.svelte      # /about
└── blog/
    ├── +page.svelte       # /blog
    └── [slug]/
        └── +page.svelte   # /blog/:slug

Route Files

FilePurpose
+page.sveltePage component (renders the UI)
+page.tsUniversal load function (runs on server AND client)
+page.server.tsServer-only load function (database, secrets)
+layout.svelteShared layout wrapper (persists across child routes)
+layout.tsLayout load function
+server.tsAPI endpoint (GET, POST, etc.)
+error.svelteError page for this route segment

Dynamic Parameters

src/routes/blog/[slug]/+page.svelte

Access the parameter in a load function:

// +page.ts
export function load({ params }) {
  return {
    post: getPost(params.slug)
  };
}

Layouts

Layouts wrap child routes. They persist across navigation (no remount):

<!-- src/routes/+layout.svelte -->
<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
</nav>

{@render children()}

Nested layouts stack. A layout at src/routes/blog/+layout.svelte wraps all /blog/* pages and itself is wrapped by the root layout.

API Endpoints

// src/routes/api/users/+server.ts
import { json } from '@sveltejs/kit';

export async function GET() {
  const users = await db.getUsers();
  return json(users);
}

export async function POST({ request }) {
  const data = await request.json();
  const user = await db.createUser(data);
  return json(user, { status: 201 });
}

Gotcha: +server.ts files can’t coexist with +page.svelte in the same directory if both handle GET requests. SvelteKit won’t know which one to use.