File-based Routing
In react-router you declare routes in JavaScript. In Next.js you create files in a pages/ or app/ directory. SvelteKit works like Next.js App Router: create a folder, add +page.svelte, and you have a route. No imports, no route config, no wrapping component needed.
Run this in a SvelteKit project (
npx sv create).
Basic routes
Section titled “Basic routes”The simplest case: a static path maps directly to a folder + +page.svelte.
// react-router v6import { createBrowserRouter } from 'react-router-dom';import About from './pages/About';
const router = createBrowserRouter([ { path: '/about', element: <About /> },]);<!-- src/routes/about/+page.svelte --><!-- This file IS the /about route. No config needed. -->
<h1>About</h1><p>Welcome to the about page.</p>Dynamic routes: [param]
Section titled “Dynamic routes: [param]”react-router uses :id in the path string. Next.js uses [id] in the filename. SvelteKit uses [param] as a folder name — the folder name (without brackets) becomes the parameter key.
// react-router v6{ path: '/posts/:id', element: <PostPage /> }
// Next.js Pages Router// pages/posts/[id].tsx
// Next.js App Router// app/posts/[id]/page.tsx<!-- src/routes/posts/[id]/+page.svelte --><!-- Matches /posts/1, /posts/hello, /posts/anything -->
<h1>Post detail page</h1>Route file-tree walkthrough
Section titled “Route file-tree walkthrough”A realistic SvelteKit src/routes/ structure:
flowchart TB routes(["src/routes/"]) routes --> rootPage["+page.svelte → /"] routes --> about["about/"] about --> aboutPage["+page.svelte → /about"] routes --> blog["blog/"] blog --> blogPage["+page.svelte → /blog"] blog --> slug["[slug]/"] slug --> slugPage["+page.svelte → /blog/:slug"] routes --> dashboard["dashboard/"] dashboard --> dashLayout["+layout.svelte (shared layout)"] dashboard --> dashPage["+page.svelte → /dashboard"] dashboard --> settings["settings/"] settings --> settingsPage["+page.svelte → /dashboard/settings"]
Every +page.svelte is a route. The +layout.svelte inside dashboard/ wraps all pages in that folder and its subfolders — equivalent to a <Outlet> layout route in react-router or a layout.tsx in Next.js App Router.
Nested layouts
Section titled “Nested layouts”A +layout.svelte at any level wraps every route in that folder and its child folders — this maps to layout.tsx in Next.js App Router or an <Outlet> layout route in react-router:
// react-router v6 — nested layout{ path: '/dashboard', element: <DashboardLayout />, children: [ { index: true, element: <DashboardHome /> }, { path: 'settings', element: <Settings /> }, ]}
// DashboardLayout.jsximport { Outlet } from 'react-router-dom';function DashboardLayout() { return ( <div> <nav>Dashboard nav</nav> <Outlet /> </div> );}<!-- src/routes/dashboard/+layout.svelte --><script> let { children } = $props();</script>
<nav>Dashboard nav</nav>{@render children()}
<!-- src/routes/dashboard/+page.svelte --><h1>Dashboard Home</h1>
<!-- src/routes/dashboard/settings/+page.svelte --><h1>Settings</h1>{@render children()} inside +layout.svelte is where the child page is rendered — the direct equivalent of react-router’s <Outlet />. Every folder level can have its own +layout.svelte; layouts nest without limit.
Accessing route params
Section titled “Accessing route params”Via the load function (recommended)
Section titled “Via the load function (recommended)”The cleanest approach is to read params inside +page.js or +page.server.js and pass them to the component as data. The component stays param-agnostic.
export async function load({ params }) { const post = await fetchPost(params.slug); return { post };}<script> let { data } = $props(); // data.post is what load() returned</script>
<h1>{data.post.title}</h1><article>{@html data.post.content}</article>Via the $page store (direct access)
Section titled “Via the $page store (direct access)”You can also read params directly in the component using the $page store from $app/state:
<script> import { page } from '$app/state'; // page.params.slug is the current [slug] value</script>
<p>Viewing slug: {page.params.slug}</p>The load function approach is preferred — it keeps data fetching co-located and typed, and it works well with server-side rendering.