Svelte Framework

SvelteKit

SvelteKit is Svelte's official application framework. It adds file-based routing, server-side load functions, form actions and adapters that deploy anywhere.

intermediate14 min readUpdated Sep 15, 2026
+page.server.js
js
// src/routes/blog/[slug]/+page.server.js
import { error } from "@sveltejs/kit";

export async function load({ params, fetch }) {
  const res = await fetch(`/api/posts/${params.slug}`);
  if (!res.ok) throw error(404, "Post not found");

  return { post: await res.json() };
}
Built on
Svelte
Router
File-based (src/routes)
Data
load functions
Mutations
Form actions
Server
Node, serverless, edge
Deploy
Adapters for any target

Why it matters

Why SvelteKit is the default Svelte setup

Routing without config

Folders and special files define routes, layouts, loading states and error pages with no route table to maintain.

Data loading on the server

load functions run on the server or at the edge, so pages arrive with data already resolved.

Adapters for every host

One build can target Node, static hosting, Vercel, Netlify, Cloudflare and more by swapping an adapter.

The big picture

The three ideas behind SvelteKit

Files define routes, load functions fetch data on the server, and adapters turn the same app into any deployment target.

The router

Navigation

+page, +layout and +server files define pages, shared UI and API endpoints.

Load functions

Data

Server or universal functions that fetch data before a page renders.

Adapters

Deployment

Build output is shaped for the platform you deploy to.

SvelteKit at a glance

What SvelteKit adds to Svelte

File-based routes

src/routes maps folders and files to URLs, including dynamic parameters.

Layouts

+layout files wrap child routes and can nest for shared shells.

Load functions

Fetch data before rendering, on the server or in the browser.

Form actions

Handle form submissions on the server with progressive enhancement.

API endpoints

+server.js files export GET, POST and other HTTP handlers.

Hooks

Run logic on every request for auth, logging and locals.

A short history

From Sapper to the official framework

  1. 2017

    Sapper

    The first Svelte application framework introduces file-based routing and SSR.

    17
  2. 2020

    SvelteKit announced

    Sapper's successor is designed around adapters and web standards.

    20
  3. 2021

    Public beta

    SvelteKit stabilises its routing, load and form APIs.

    21
  4. 2022

    SvelteKit 1.0

    A stable release becomes the recommended way to build Svelte apps.

    22
  5. Today

    Paired with Svelte 5

    SvelteKit embraces runes and remains the official application framework.

    Today

The complete guide

SvelteKit: Everything you need to know

What is SvelteKit?

SvelteKit is the official application framework for Svelte. Svelte gives you components and reactivity; SvelteKit adds routing, server-side data loading, form handling, API endpoints and deployment adapters. It is the recommended way to build anything larger than a widget, and it pairs naturally with Svelte 5.

If you have used Next.js or Nuxt, the shape will feel familiar. The difference is a strong bias toward web standards: forms, requests and responses are platform primitives, and SvelteKit enhances them rather than replacing them.

File-based routing

Everything lives in src/routes. Folders become URL segments, and specially named files define behaviour.

src/routes/
├── +layout.svelte          # shared shell for all routes
├── +page.svelte            # /
├── about/+page.svelte      # /about
├── blog/
│   ├── +page.svelte        # /blog
│   └── [slug]/
│       ├── +page.svelte    # /blog/:slug
│       └── +page.server.js # data for that page
└── api/
    └── posts/+server.js    # GET/POST /api/posts

The + prefix marks SvelteKit’s special files. +page.svelte renders a page, +layout.svelte wraps child routes, +page.server.js provides server-only data, and +server.js defines an API endpoint.

Load functions

Load functions fetch data before a page renders. They can run on the server, in the browser, or both.

// src/routes/posts/+page.server.js
export async function load({ fetch }) {
  const res = await fetch("/api/posts");
  if (!res.ok) throw error(500, "Failed to load posts");
  return { posts: await res.json() };
}
<!-- src/routes/posts/+page.svelte -->
<script>
  let { data } = $props();
</script>

<ul>
  {#each data.posts as post (post.id)}
    <li>{post.title}</li>
  {/each}
</ul>

Because the data is resolved before render, the first paint already has content. Use +page.server.js when the code needs secrets or a database, and +page.js when it can run in both places. Layouts can also have load functions, and child loads receive the parent’s data.

Form actions

Forms are first-class. A form action runs on the server and handles the submission, with no client-side fetch required.

// src/routes/posts/new/+page.server.js
export const actions = {
  default: async ({ request }) => {
    const data = await request.formData();
    const title = String(data.get("title") ?? "").trim();

    if (!title) {
      return { success: false, error: "Title is required" };
    }

    await db.post.create({ data: { title } });
    return { success: true };
  },
};
<!-- src/routes/posts/new/+page.svelte -->
<script>
  let { form } = $props();
</script>

<form method="POST">
  <input name="title" />
  {#if form?.error}<p class="error">{form.error}</p>{/if}
  <button>Create</button>
</form>

The form works before JavaScript loads, and SvelteKit enhances it once the client is ready. The returned value is available in the page’s form prop, so validation feedback is simple.

API endpoints

For JSON APIs, a +server.js file exports HTTP handlers.

// src/routes/api/posts/+server.js
import { json } from "@sveltejs/kit";

export async function GET() {
  const posts = await db.post.findMany();
  return json(posts);
}

export async function POST({ request }) {
  const body = await request.json();
  const post = await db.post.create({ data: body });
  return json(post, { status: 201 });
}

These are ordinary web Request and Response objects, so the same knowledge transfers to other runtimes and frameworks.

Hooks

A hooks.server.js file runs on every request. It is the place for authentication, logging and populating event.locals.

// src/hooks.server.js
export async function handle({ event, resolve }) {
  const session = await getSession(event.cookies);
  event.locals.user = session?.user ?? null;

  return resolve(event);
}

Anything you set on locals is available to load functions and actions, which keeps cross-cutting concerns in one place instead of scattered across routes.

Rendering and adapters

SvelteKit supports several rendering strategies and lets you choose per route:

  • SSR renders on the server and hydrates in the browser.
  • Prerendering generates static HTML at build time.
  • CSR renders only in the browser for routes that opt out.
  • Hybrid mixes all three, so a marketing page can be static while an app route is server-rendered.

Deployment is handled by adapters. Install the adapter for your target — Node, static, Vercel, Netlify, Cloudflare and more — configure it, and the same source builds for that platform. Switching hosts is usually a one-line change.

Best practices

  • Use +page.server.js load functions for data that must stay on the server.
  • Prefer form actions over client-side POST requests for mutations.
  • Keep authentication and logging in hooks.server.js.
  • Choose the narrowest rendering mode that fits each route.
  • Use +layout.svelte for shared UI so state persists across navigation.
  • Type your load function return values when using TypeScript.
  • Install an adapter that matches your deployment target from the start.

Common mistakes

  • Fetching in onMount and losing server rendering.
  • Putting secrets in a universal +page.js load instead of +page.server.js.
  • Rebuilding forms with client-side fetch when actions already work.
  • Forgetting to key {#each} blocks and breaking list updates.
  • Prerendering a route that depends on per-user data.
  • Ignoring hooks and duplicating auth checks in every load function.

Where to go next

SvelteKit is the complete way to build with Svelte. Deepen your Svelte knowledge, add TypeScript, and compare the architecture with Next.js, Nuxt and Astro. Then build a small app with a load function, a form action and an API endpoint to see the whole model in action.

Loading data

A load function runs before the page renders, on the server. Fetching in onMount happens later and flashes empty content.

Prefer
// +page.js
export async function load({ fetch }) {
  const res = await fetch("/api/posts");
  return { posts: await res.json() };
}
Avoid
<script>
  import { onMount } from "svelte";
  let posts = [];
  onMount(async () => {
    posts = await fetch("/api/posts")
      .then((r) => r.json());
  });
</script>

Handling forms

A form action runs on the server and works without JavaScript, then enhances automatically when JS is available.

Prefer
// +page.server.js
export const actions = {
  default: async ({ request }) => {
    const data = await request.formData();
    await createPost(data.get("title"));
  },
};
Avoid
<script>
  async function submit(e) {
    e.preventDefault();
    await fetch("/api/posts", {
      method: "POST",
      body: new FormData(e.target),
    });
  }
</script>

FAQ

Frequently asked questions

Keep learning

Related topics from the roadmap.

$ start learning

Ready to start learning SvelteKit?

Our interactive tutorial walks you through SvelteKit step by step — with quizzes and real code you can run in the browser.