03 - Routing

📋 Jump to Takeaways

File-Based Routing

Routes are defined by the folder structure in src/routes/. Each folder with a +page.svelte becomes a URL.

Basic Routes

src/routes/
├── +page.svelte              → /
├── about/
│   └── +page.svelte          → /about
└── blog/
    ├── +page.svelte          → /blog
    └── [slug]/
        └── +page.svelte      → /blog/hello-world (dynamic)

Dynamic Routes

Square brackets [param] create dynamic segments. The value is available via params in load functions.

This example uses +page.ts (runs on server and browser). If you need database access or secrets, use +page.server.ts instead, and change PageLoad to PageServerLoad. We cover the difference in the Loading Data lesson.

// src/routes/blog/[slug]/+page.ts
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params }) => {
  // params.slug = "hello-world" when URL is /blog/hello-world
  return {
    post: {
      title: params.slug,
      content: 'Post content...'
    }
  };
};

OR this simpler (untyped) version does the same thing:

export const load = ({ params }) => {
    return { slug: params.slug };
};
<!-- src/routes/blog/[slug]/+page.svelte -->
<script lang="ts">
let { data } = $props();  // data comes from the load function above
</script>

<h1>{data.slug}</h1>

Multiple Parameters

Each folder level can have its own parameter:

src/routes/
└── [category]/
    └── [id]/
        └── +page.svelte      → /electronics/123

params would be { category: "electronics", id: "123" }.

Optional Parameters

Double brackets [[param]] make a segment optional — the route matches with or without it:

src/routes/
└── [[lang]]/
    └── +page.svelte          → / or /en or /fr

Rest Parameters

[...param] captures all remaining segments as a single string:

src/routes/
└── docs/
    └── [...path]/
        └── +page.svelte      → /docs/a/b/c

params.path would be "a/b/c".

Two ways to navigate between pages:

<script>
import { goto } from '$app/navigation';
</script>

<!-- Declarative — standard <a> tags, SvelteKit handles them as client-side navigation -->
<a href="/about">About</a>

<!-- Programmatic — navigate from code (after form submit, button click, etc.) -->
<button onclick={() => goto('/about')}>Go to About</button>

SvelteKit intercepts <a> clicks automatically — no special <Link> component needed.

Route Groups

Parentheses (name) create layout groups — they organize routes without affecting URLs:

src/routes/
├── (marketing)/
│   ├── +layout.svelte       ← marketing layout (no nav bar)
│   ├── about/+page.svelte   → /about
│   └── contact/+page.svelte → /contact
└── (app)/
    ├── +layout.svelte       ← app layout (with sidebar, auth)
    └── dashboard/+page.svelte → /dashboard

The (marketing) and (app) folders don't appear in the URL. They just let you apply different layouts to different groups of pages.

Key Takeaways

  • Routes are defined by folder structure in src/routes/ — each folder with a +page.svelte becomes a URL
  • Dynamic routes use [param] brackets, accessed via params in load functions (e.g., params.slug)
  • Optional parameters use [[param]], rest parameters use [...param] to capture multiple segments
  • Navigate declaratively with <a href="/path"> (SvelteKit intercepts clicks automatically) or programmatically with goto('/path') from $app/navigation
  • Route groups (name) organize routes under different layouts without affecting URLs
  • Multiple dynamic segments are supported: src/routes/[category]/[id]/+page.svelteparams.category, params.id
  • Load functions in +page.ts use PageLoad type; use +page.server.ts with PageServerLoad when you need DB or secret access

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

© 2026 ByteLearn.dev. Free courses for developers. · Privacy