A First Look at SvelteKit

Originally published on 26 March, 2021 by Jacob Stordahl

If you've been using Svelte or Sapper over the past year, you've probably heard about SvelteKit. SvelteKit emerged as a unified way to build Svelte apps and aims to solve many problems presented by the template-based workflow of Svelte 3 and the general confusion about when to use Sapper and when to use Vanilla Svelte. We've all been anxiously waiting for any look into how this new system will work, and as of March 11, 2021, SvelteKit is now open source and available to be tested!

So today let's dive in a checkout SvelteKit, how it works, and the problems it aims to solve. Let's tackle these in reverse order.

Problems with Sapper

As Rich Harris, the original creator of Svelte, says in the first look at SvelteKit, Sapper was first built in 2017 & the web development landscape has changed significantly since then. The current code-base for Sapper make it difficult to add valuable features like partial static rendering and optimization for serverless platforms. Sapper also introduced some confusion around which projects should use the standard Svelte template and which should use Sapper. Rich and the maintainers saw this as an opportunity to start fresh with a single unified way to build Svelte apps of any shape or size: this is SvelteKit.

My first impressions of SvelteKit is that the core team really focused on patterns for building complex applications, specifically data driven applications. Let's take a birds eye view of the most important concepts that SvelteKit brings to the table.

How it works

App Structure

The structure of a SvelteKit app is very similar to Sapper in that it includes a src directory which itself contains three things; app.html where our Svelte code is injected at build/render, a directory named lib and another named routes. In the same fashion as Sapper, routes is where the structure of our app is defined: each .svelte file or folder containing an index.svelte file will become a route in our app. lib is interesting because it introduces us to a new feature that SvelteKit provides: path aliasing.

If we open up jsconfig.json in the root of our project, we see a JSON object which contains an include property and an object of compilerOptions.

// jsconfig.json
	"compilerOptions": {
		"baseUrl": ".",
		"paths": {
			"$app/*": [".svelte/dev/runtime/app/*", ".svelte/build/runtime/app/*"],
			"$lib/*": ["src/lib/*"]
	"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]

Within the compiler options we have a property called paths where we can create aliases for different commonly used paths in our code-base. This removes the need for endless strings of ../../../etc. By default the aliases created are $app and $lib. We can see an alias in action in index.svelte where we're importing a <Counter /> component that is in our lib directory by setting the path to $lib/Counter.svelte. What a cool feature!

Returning to the routes directory, I want to quickly point out two changes from Sapper; layout components work in exactly the same way, however these files should be prepended with a $ instead of an _. The underscore is now exclusively denotes a Private Module, meaning it can be referenced by other components, but will not generate its own route at build time.

The Loading API

The next feature we're going to look at is the Loading API within SvelteKit. Any Svelte component that defines a page can export a load function within a <script context="module"> which will run before the component is created. This removes the need for loading states and fetching data onMount. Look forward to a separate post that will deep dive on the useful patterns for data fetching that arise from this new API.


In a SvelteKit app, we can create a hooks.js file in the src directory which exports three functions that run on the server side: getContext, getSession, & handle. Again, these functions will get there own in-depth tutorial, however the important thing to know is they all give very intuitive patterns for dealing with users, sessions, cookies, etc.


Adapters are likely my favorite feature of SvelteKit. These packages provide a dead simple way to configure the build step of your app based on the intended deployment. By default, a SvelteKit app comes with adapter-node preinstalled. We can see this configuration in svelte.config.cjs

// svelte.config.cjs
const node = require('@sveltejs/adapter-node');

module.exports = {
	kit: {
		adapter: node()

This adapter property tells SvelteKit how to compile our app be it as a standard Node.js app, a set of static HTML pages, or a bundle optimized for a particular hosting provider. There are already adapters for the most popular providers like Netlify and Vercel.

Honorable Mentions

There are a ton of new features introduced by SvelteKit that I don't have time to touch on in this article. Here are some smaller features that are worth reading about in the docs...

  • SvelteKit CLI for running your app 🏃‍♂️
  • New API for pre-rendering specific pages
  • Similar to Sapper an anchor tag with a sveltekit:prefetch attribute will prefetch the page on hover
  • Modules are a new set of APIs that provide information about your app like root path, current environment, and available stores (among other things)
  • Creating endpoints within your app is still available and works just as it did in Sapper
© 2021 Jacob Stordahl | built with Steel