Thilo Maier

Route matching in SvelteKit

Thilo Maier •
Last modified:

This post is outdated for SvelteKit 1.x. It covers SvelteKit's router before SvelteKit 1.0.0-next.406.

The SvelteKit docs state that

At the heart of SvelteKit is a filesystem-based router. This means that the structure of your application is defined by the structure of your codebase — specifically, the contents of src/routes.

In this post, we will explore how SvelteKit's filesystem-based router matches a requested route to a page or an endpoint. SvelteKit transforms each route file in src/routes into a page or an endpoint. Conversely, SvelteKit needs to match a requested route to a route file. This is called route matching.

A filesystem-based router makes route matching straightforward: the route can be interpreted as the subpath in src/routes and often there is only one matching route file. But what happens when there are multiple matching route files? How does SvelteKit decide which route file it uses to render a page or endpoint?

In this post, we look at a SvelteKit example and explore the rules that SvelteKit applies to decide which page or endpoint to serve. You will make the most out of this post if you follow along:

Duplicate route files are not permitted

When you have the example up and running, click route /green in the preview. SvelteKit matches this request to page src/routes/green.svelte. This is the filesystem-based router at work, which takes the route and looks for the corresponding route file in src/routes.

Now click route /red. This time SvelteKit matches the request to page src/routes/red/index.svelte, which is equivalent to src/routes/red.svelte.

Create file src/routes/red.svelte in the example and copy the content of file src/routes/red/index.svelte. You should see this error message in the terminal:

$ svelte-kit dev
> Duplicate route files: src/routes/red

Rule 1: Duplicate route files are not permitted.

You cannot have both src/routes/red/index.svelte and src/routes/red.svelte. SvelteKit won't let you.

Delete src/routes/red.svelte and run

npm run dev

to restart the development server.

Matching against path segments

The SvelteKit router matches strings of route segments to path segments. Path segments inside src/routes can be static (.../static/...) or dynamic ( .../[dynamic]/...) with square brackets. Dynamic path segments match any string. Static path segments require an exact match. The second rule describes the order in which SvelteKit matches route segments to path segments:

Rule 2: SvelteKit matches route segments to path segments left to right.

Let's revisit the /red route from before. Now that we know what dynamic path segments are, we realize that there were three more candidate pages:

  • src/routes/[color].svelte
  • src/routes/[nocolor].svelte
  • src/routes/[colour]/index.svelte

These are not duplicate routes because the strings inside [] differ. We already know from the previous section, that /red is not rendered with any of the above candidate pages. The reason is this rule:

Rule 3: Static path segments take precedence over dynamic path segments.

E.g., src/routes/green.svelte (static) takes precedence over src/routes/[color].svelte (dynamic).

Alphabetical order of path segments

Let's look at route /blue in the example. The candidate pages are:

  • src/routes/[color].svelte
  • src/routes/[nocolor].svelte
  • src/routes/[colour]/index.svelte

We need another rule to choose the page that is used to render /blue:

Rule 4: Index pages take precedence over non-index pages.

This is only relevant for pages that are not considered duplicate routes, e.g., src/routes/[colour]/index.svelte takes precedence over src/routes/[color].svelte.

When matching route segment blue, we can use this rule to eliminate the first two candidate pages. This results in page src/routes/[colour]/index.svelte being rendered. You can confirm this by clicking on /blue in the example.

Let's delete page src/routes/[colour]/index.svelte in the example. To make the workspace pick up this change, you need to click in the terminal and hit ⌃C. Restart the development server with npm run dev.

Now the two candidates for route /blue are:

  • src/routes/[color].svelte
  • src/routes/[nocolor].svelte

A look at the rendered page reveals that the router used src/routes/[color].svelte. It did so because of this rule:

Rule 5: For two path segments of the same type, the first one in alphabetical order takes precedence.

E.g., src/routes/[color].svelte takes precedence over src/routes/[nocolor].svelte because color comes before nocolor in alphabetical order.

Matching with spread syntax

Let's look at route /color/blue in the example. The candidate pages are:

  • src/routes/color/[color].svelte
  • src/routes/color/[...rest].svelte

[...rest] in the second route is a dynamic path segment, which uses spread syntax and matches any path under /color, no matter how deep. We refer to it as a spread segment. The following rule clarifies, which page the router chooses to render /color/blue:

Rule 6: Dynamic path segments take precedence over spread segments.

E.g., src/routes/color/[color].svelte takes precedence over src/routes/color/[...rest].svelte.

You can navigate to route /color/blue/dark to see an example of a route that is rendered with src/routes/color/[...rest].svelte.

Error pages

Last but not least, let's navigate to route /blue/dark in the example. This time, there are no candidate pages. What does the router do? It falls back to default error page src/routes/+error.svelte.

Note that as soon as there is one candidate page, including pages with spread segments, the SvelteKit router does not fall back to an error page. This is what we observed for route /color/blue/dark in the previous section. It was rendered with src/routes/color/[...rest].svelte and not the default error page.

SvelteKit allows you to configure error pages more granular per directory and you can read up on how this works in the SvelteKit docs.