Intro to SvelteKit: A Beginner’s Guide

This is a beginner friendly guide that covers all the basics of SvelteKit

Creating Svelte apps just got even better thanks to SvelteKit. This new Svelte framework is intuitive and easy to use, even for beginners. It adds key features to a Svelte app, such as routing, layouts, and server-side rendering. You can think of it as an ambitious Next.js for Svelte! In this tutorial we will look at the main features SvelteKit offers, how to begin building a SvelteKit project, and how it compares to vanilla Svelte.

What is Svelte?

Before we dive into SvelteKit, let’s quickly review what Svelte is. Svelte is a lightweight component-based framework that allows JavaScript developers to write organized, easy-to-read code. Svelte is known for being faster than most other frontend frameworks due to its novel approach to building user interfaces. In a nutshell, Svelte is not actually a framework, but rather a compiler. The compiler takes the Svelte code as an input and uses it to generate the actual vanilla JavaScript code. By compiling your code during the build process into a single vanilla JavaScript file, it eliminates the need to deploy a library (like we do with other frontend frameworks). If you are interested in taking a deeper dive into vanilla Svelte, check out my last blog post.

What is SvelteKit?

SvelteKit is a lightweight component-based framework that allows JavaScript developers to create both small and large scale web applications with a smaller footprint. SvelteKit does much of the heavy lifting, making it simple to create web apps with all the modern best practices. It provides a lightning-fast development experience by leveraging Vite, which makes updates instant and precise. SvelteKit also uses svelte-preprocess package to provide built-in support for common plugins such as Babel, TypeScript, SASS etc. You can think of SvelteKit as Next.js for Svelte, complete with server-side rendering, routing, code-splitting, and adapters for different serverless platforms. It gives you the functionality you need to create a ready-to-go application, and is beginner friendly.

Why use SvelteKit?

SvelteKit is a modern framework that builds fast, high-performance web applications of all sizes while simultaneously reducing the amount of code used. It takes advantage of all the modern practices, making it an ideal framework.

Server-side Rendering

Server-side rendering (SSR) allows developers to pre-populate the web app with custom user data directly on the server. With SSR, clients receive a pre-rendered page on demand rather than waiting for specific elements to load. Single page applications, on the other hand, render the web page when the client requests them. SPAs are thus structured as a single HTML page with no preloaded content.

SvelteKit supports server-side rendering, meaning it first pre-renders the HTML on the server-side and then sends it to the user’s browser. The browser then takes over the execution. At this point, the web app behaves like an SPA. This increases the performance of the app and drives up SEO.

Adapters

Before a SvelteKit app can be deployed, you first need to adapt it for your deployment target. Adapters are small plugins that take the built app as input and generate output for deployment. They are oftentimes optimised for a specific hosting provider, however some adapters, like adapter-static, build output that can be hosted on numerous hosting providers. You can generally find information about deployment in your adapter’s documentation. For example, if you wanted to deploy your app to Vercel, you would simply add "@sveltejs/adapter-vercel": "next" to the devDependencies in your package.json and run npm install. Then in your svelte.config.js:

import vercel from '@sveltejs/adapter-vercel';
	export default {
		kit: {
			...
			adapter: vercel()
		}
	};

Getting Started

First, you can initiate a new SvelteKit project by running the following command in your terminal:

npm init svelte@next svelteKit-app

You will be prompted to answer a few questions to customize your project. You will be prompted to answer a few questions. I recommend selecting ‘SvelteKit demo app’ in response to the first. This will create a SvelteKit development environment with a functioning example project. You can also select ‘Skeleton Project’ for the first question, but the demo app is a good learning tool in project structure, so for your first project I recommend using it.

Next you need to move into the project directory to install its dependencies and run the project locally.

cd svelteKit-app
npm install
npm run dev -- --open

This will open your demo app in the browser. You’ll notice it provides you with default routing, layouts, load functions and components for you to build off of. In your project route you will see some configuration files including your package.json, the static folder, and the src folder. You will mostly be working out of the src folder, which has the following structure.

src
├── app.css
├── app.html
├── global.d.ts
├── hooks.js
├── lib
│├── Counter
││└── index.svelte
│├── form.js
│└── Header
│├── index.svelte
│└── svelte-logo.svg
└── routes
├── __layout.svelte
├── about.svelte
├── index.svelte
└── todos
├── _api.js
├── index.json.js
├── index.svelte
└── [uid].json.js

Routing

SvelteKit includes a client-side-router. It is a filesystem-based router that updates the page contents after intercepting navigations. The code structure is defined by the contents of the src/routes directory.

Routing in SvelteKit is similar to other SSR frameworks such as Next.js. It uses .svelte filenames inside of the src/routes directory to determine the pages route. For example, if you want to navigate to /home page, then SvelteKit will render a home.svelte file to the src/routes folder. The file src/routes/home.svelte will correspond to /home route. If you want to create nested routes, you need to create a folder for each sub-route. Having an index.svelte file within that folder will create a route for the folder name. This makes the navigation process extremely simple.

src
└── routes
├── home.svelte--> localhost:3000/home
└── about
├── index.svelte--> localhost:3000/about
└── products.svelte--> localhost:3000/about/products

SvelteKit also supports advanced routing such as using dynamic parameters. For example, if you need to include an ID in a route and display data associated with that ID, the route would look as follows:

localhost: 3000 / user / { id };

In order to do this, you must create a folder named user and insert files for the dynamic parameters. In the above example, we would need a file called [id].svelte, where the square bracket indicated the variable inside the dynamic parameter.

rc
└── routes
└── user
├── [id].svelte

Now that we have our [id].svelte file, we can access that dynamic parameter from the variable in the package $app/stores. Since the page variable is a store, we need to prefix the variable with $ and the dynamic parameter will be under an object called params.

<script>
import {page} from ‘$app/stores’;
</script>
<p> Display user info from: {$page.params.id} </p>

Layouts

Pages are not just standalone components. Upon navigation, the existing component will be destroyed, and a new one will take its place, but oftentimes there are elements that should be displayed on every page, such as a header or footer. Instead of adding these to every page file, we can use layout components. Components can be wrapped in a layout component using the <slot> tag, which indicates where the child component should be placed within the parent layout. To create a layout component that applies to every page, name a file src/routes/__layout.svelte. The default layout component simply contains a single <slot> tag, but we can add whatever markup, styles, and behavior we want. For example, we can add a navbar like this:

<!-- src/routes/__layout.svelte -->
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/settings">Settings</a>
</nav>
<slot></slot>

In this example, the nav bar will always be visible. The only thing changing is the content within the slot which will correspond to the / , /about, and /settings pages. SvelteKit also allows us to create nested layouts. Suppose rather than having a single /team page, we have nested pages such as /team/lead and team/creative. We are able to create a layout that only applies to pages below /team while still inheriting the root layout at the top-level. To do this, we create the layout the same way we did before, but name the file src/routes/team/__layout.svelte.

Static Pages and Prerendering

As I mentioned earlier, SvelteKit builds apps for different environments using adapters. If the app does not rely on any dynamic data, it could consist entirely of static files. There is an adapter-static that can be installed, which turns SvelteKit into a static site generator. This means that it would render the entire app into a collection of static files at build time, which would prevent us from adding pages that depend on server-side rendering.

Instead of making all of our pages static, we can use another SvelteKit feature which allows us to prerender individual files. For example, if we have an about page that consists of static content, rendering the page on every request would be unnecessary. Instead, we can prerender the page by adding the following code snippet at the top of the about.svelte file:

<script context="module">export const prerender = true;</script>

Endpoints

So now we know how to render static pages, but what if we want to fill our page with dynamic content? To do this, we need to fetch our data from an API endpoint. Usually this would come from the backend, but SvelteKit makes it simple to turn your application full stack using endpoint pages. These modules are written in .js (or .ts) and export functions corresponding to HTTP methods. For example, a hypothetical blog page, /blog/article, might request data from /blog/article.json, which could be represented by a src/routes/blog/[slug].json.js endpoint:

import db from '$lib/database';
/**
 * @type {import('@sveltejs/kit').RequestHandler}
 */
export async function get({ params }) {
	// the `slug` parameter is available because this file
	// is called [slug].json.js
	const { slug } = params;
	const article = await db.get(slug);
	if (article) {
		return {
			body: {
				article
			}
		};
	}
}

This function will return a { status, headers, body } object representing the response, where the status is the HTTP status code. Endpoints also have access to fetch in case you need to request data from external APIs. For endpoints that handle other HTTP methods, like POST, export the corresponding function:

export function post(request) {...}

Loading

Each page or a layout can export a load function which will run before the component is created. This function runs both during server-side rendering and in the client, allowing you to get the necessary data for the page without needing to show a loading spinner and fetching data onMount. This function receives an object as the input, and the value it returns is passed to the page as a prop. If you return a promise, the page will not be rendered until the promise is resolved.

Conclusion

Both Svelte and SvelteKit are extremely intuitive and easy to learn. If you are wondering when to use Svelte vs SvelteKit, I would argue that 99% of the time SvelteKit is the answer. It can do everything Svelte can do and more, making it even more powerful and an overall better developer experience. SvelteKit streamlines the entire stack into a single, file-based layout which is then used to provide a consistent development experience for multiple production environments. SvelteKit provides all the benefits of Svelte, as well as a multitude of end-to-end features for building dynamic, data-driven apps. While SvelteKit is akin to Next.js, it is even more ambitious, and I believe it is the future of web development.

Email: steph.dietz@vercel.com