Skip to content

Instantly share code, notes, and snippets.

@amxv
Last active August 21, 2025 03:07
Show Gist options
  • Save amxv/45025aa6fecd1a3b74f15091a546fced to your computer and use it in GitHub Desktop.
Save amxv/45025aa6fecd1a3b74f15091a546fced to your computer and use it in GitHub Desktop.
Svelte 5 and SvelteKit Cursor Rules (scroll down to see sveltekit.mdc) - Pop these in the `.cursor/rules` folder in the root of your project.
---
description: writing svelte code
globs: *.svelte, *.svelte.ts
---
In this project, we use Tailwind CSS for styling and shacn-svelte as the UI component library (built on top of Bits UI).
It is a port of shadcn/ui to Svelte. You can use their CLI to install all the same shadcn components by running this command `bunx shadcn-svelte@next add <component-1> <component-2>`, just like the Original React version.
Please use the new Svelte 5 syntax when working in .svelte and .svelte.ts files.
Some key points include:
- Using the new runes syntax ($state, $derived, etc.) to manage reactive state variables instead of the `$: ` syntax of Svelte 4.
- Using the new event handler syntax (onclick instead of on:click - the colon should not be included)
- Using snippets instead of slots.
- Using the $props() syntax to extract props, avoid using the old `export let props` syntax.
- Use `$app/state` instead of `$app/stores`, then you can just access state objects like `page.url.pathname`.
Current Path Aliases:
- "@components": "./src/components"
- "@utils": "./src/utils"
- "@utils.js": "./src/utils"
- "@hooks": "./src/hooks"
- "@src": "./src"
- "@server": "./src/lib/server"
- "@api": "./src/lib/api"
- "@types": "./src/types"
- "@schemas": "./src/schemas"
- "@state": "./src/lib/state"
- "@db": "./src/lib/server/db"
Please read the file `ai-docs/svelte.txt` at the root of this project which includes the full svelte 5 documentation if you are unsure or notice that you made a lint error while writing some code. This should help you with the correct syntax.
Below is a cheat sheet that explains all the features of Svelte 5 in a concise way.
---
# Svelte 5 Cheat Sheet
This cheat sheet provides a quick guide to the essential features of Svelte 5, focusing on the new runes syntax for reactivity and component structure.
## .svelte files
`.svelte` files are the foundation of Svelte applications, defining reusable components. They combine HTML markup with JavaScript logic and CSS styles, all within a single file. A `.svelte` file is structured into three optional blocks: `<script>` for component logic, `<!-- markup -->` for HTML structure, and `<style>` for component-specific CSS. The `<script>` block is where you'll write JavaScript, using runes to manage reactivity and props. Styles within `<style>` are automatically scoped to the component, preventing CSS conflicts with other parts of your application.
```svelte
/// file: MyComponent.svelte
<script>
let name = $state('World'); // Reactive state
</script>
<h1>Hello, {name}!</h1>
<style>
h1 { color: blue; } /* Styles scoped to this component */
</style>
```
## .svelte.js and .svelte.ts files
Svelte 5 introduces `.svelte.js` (or `.svelte.ts` for TypeScript) files for creating reusable JavaScript modules that can leverage runes. These files are similar to regular `.js` or `.ts` modules but allow you to use runes for reactive logic outside of components. This is particularly useful for sharing reactive state or encapsulating complex reactive functions that can be imported and used across different components. This feature promotes code reusability and helps in organizing reactive logic in larger applications.
```javascript
/// file: reactive-utils.svelte.js
export const count = $state(0);
export function increment() {
count.set(count + 1);
}
```
## What are runes?
Runes are special symbols in Svelte 5, prefixed with a `$`, that are used to control the Svelte compiler and manage reactivity. Think of them as keywords that are built into the Svelte language. Unlike regular JavaScript functions, runes don't need to be imported and cannot be assigned to variables or passed as function arguments directly. They are used to declare reactive state, derived values, effects, and component props, fundamentally changing how reactivity is handled in Svelte 5 compared to previous versions.
```js
let message = $state('Hello Svelte 5!'); // $state rune to create reactive state
let doubled = $derived(count * 2); // $derived rune for derived values
```
## $state
The `$state` rune is the primary way to declare reactive variables in Svelte 5. Variables created with `$state` automatically trigger UI updates whenever their value changes. You initialize `$state` with an initial value, and then you can directly update the variable like any normal JavaScript variable. For objects and arrays, `$state` creates a *deeply reactive proxy*, meaning changes within nested properties or array elements will also trigger reactivity.
```svelte
<script>
let count = $state(0); // Reactive number
</script>
<button on:click={() => count++}>Clicks: {count}</button>
```
For non-deeply reactive state, use `$state.raw`:
```js
let person = $state.raw({ name: 'Alice' }); // Not deeply reactive
person = { name: 'Bob' }; // Reassignment works
```
To get a static snapshot of a `$state` proxy, use `$state.snapshot()`:
```js
console.log($state.snapshot(counter)); // Logs a plain object, not a Proxy
```
## $derived
The `$derived` rune creates values that are automatically updated whenever their dependencies change. Derived values are read-only and are defined by an expression that depends on other reactive state (declared with `$state` or other `$derived` values). Svelte efficiently recalculates derived values only when necessary and when they are actually accessed in the template or other reactive contexts. This is crucial for performance as it avoids unnecessary computations.
```svelte
<script>
let count = $state(10);
let doubled = $derived(count * 2); // `doubled` updates when `count` changes
</script>
<p>{count} doubled is {doubled}</p>
```
For more complex derivations, use `$derived.by` with a function body:
```svelte
let numbers = $state([1, 2, 3]);
let total = $derived.by(() => { // More complex logic
let sum = 0;
for (const n of numbers) {
sum += n;
}
return sum;
});
```
## $effect
The `$effect` rune allows you to perform side effects in response to reactive state changes. Effects are functions that run after the component is mounted and re-run whenever any of the reactive values they depend on change. This is useful for tasks like DOM manipulation, integrating with external libraries, or logging. Effects should be used sparingly and are best suited for synchronizing with external systems, not for managing internal component state, which is better handled with `$derived`.
```svelte
<script>
let color = $state('red');
let canvas;
$effect(() => { // Effect runs when `color` changes
const ctx = canvas.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(10, 10, 50, 50);
});
</script>
<canvas bind:this={canvas} width="100" height="100"></canvas>
```
Effects can also return a cleanup function:
```svelte
$effect(() => {
const timer = setInterval(() => { /* ... */ }, 1000);
return () => clearInterval(timer); // Cleanup on re-run or unmount
});
```
For effects that need to run *before* DOM updates, use `$effect.pre`.
## $props
The `$props` rune is used to access properties passed to a Svelte component from its parent. Inside a component, `$props()` returns an object containing all the props. It's common to destructure props directly in the `<script>` block for easier access and to define default values. Props are reactive, meaning when a parent component updates a prop value, the child component automatically re-renders.
```svelte
/// file: MyComponent.svelte
<script>
let { name = 'Guest' } = $props(); // Destructure and set default
</script>
<p>Hello, {name}!</p>
```
You can also rename props during destructuring:
```js
let { 'data-id': id } = $props(); // Rename `data-id` to `id`
```
Use rest props to collect remaining props:
```js
let { a, b, ...rest } = $props(); // Collect remaining props into `rest`
```
## $bindable
The `$bindable` rune is used in child components to create props that can be bound by parent components using `bind:`. This enables two-way data binding, allowing changes in the child component to update the bound variable in the parent. Use `$bindable` sparingly as it can make data flow harder to track, but it's useful for components like form inputs where two-way binding is often desired.
```svelte
/// file: FancyInput.svelte
<script>
let { value = $bindable() } = $props(); // `value` is bindable
</script>
<input bind:value={value} />
```
In the parent component:
```svelte
/// file: App.svelte
<script>
import FancyInput from './FancyInput.svelte';
let message = $state('Initial message');
</script>
<FancyInput bind:value={message} /> <p>{message}</p>
```
You can also provide a fallback value for `$bindable`:
```js
let { value = $bindable('default value') } = $props();
```
## $inspect
The `$inspect` rune is a debugging tool similar to `console.log`, but it automatically re-runs whenever its arguments change, providing live updates in the console. It deeply tracks reactive state, so changes within objects or arrays will also trigger `$inspect`. This is helpful for observing reactive values and understanding data flow during development.
```svelte
<script>
let count = $state(0);
let message = $state('Hello');
$inspect(count, message); // Logs `count` and `message` whenever they change
</script>
```
Use `$inspect(...).with(callback)` for custom logging or debugging actions:
```svelte
$inspect(count).with((type, count) => {
if (type === 'update') {
debugger; // Breakpoint on update
}
});
```
For tracing the origin of effects, use `$inspect.trace()` within an effect.
## $host
The `$host` rune is specifically for components compiled as custom elements. It provides access to the custom element's host element (the element in the DOM that represents your custom element). This is useful for dispatching custom events from your component to the outside world, allowing parent pages or frameworks to react to events originating from your custom element.
```svelte
/// file: Stepper.svelte
<svelte:options customElement="my-stepper" />
<script>
function dispatch(type) {
$host().dispatchEvent(new CustomEvent(type));
}
</script>
```
## Basic markup
Svelte markup is an extension of HTML, allowing you to embed JavaScript expressions and use special tags and directives. You can use standard HTML tags like `<div>`, `<p>`, etc., and also component tags (capitalized or dot-notated) to include other Svelte components. Attributes can be static HTML attributes or dynamic JavaScript expressions enclosed in curly braces `{}`. Event listeners are added using `on:eventname` attributes.
```svelte
<script>
let dynamicClass = 'active';
let message = $state('Click me');
function handleClick() { alert('Clicked!'); }
</script>
<div class="{dynamicClass}">
<button on:click={handleClick}>{message}</button>
</div>
```
Text expressions are also enclosed in curly braces: `{expression}`. Use `{@html expression}` to render raw HTML. Comments are standard HTML comments `<!-- -->`.
## {#if ...}
`{#if ...}` blocks conditionally render content based on a JavaScript expression. You can use `{:else if ...}` and `{:else}` to create more complex conditional rendering logic. The content inside the `{#if}` block is only added to the DOM if the condition is truthy, and removed if it becomes falsy.
```svelte
<script>
let isLoggedIn = $state(false);
</script>
{#if isLoggedIn}
<p>Welcome back!</p>
{:else}
<p>Please log in.</p>
{/if}
```
## {#each ...}
`{#each ...}` blocks are used to iterate over arrays or iterable objects and render a list of elements. You can access the current item and optionally the index within the loop. Keyed each blocks `{#each items as item (item.id)}` are important for performance when lists are reordered or modified, helping Svelte efficiently update the DOM.
```svelte
<script>
let items = $state(['Apple', 'Banana', 'Cherry']);
</script>
<ul>
{#each items as item, index (item)}
<li key={item}>{index + 1}: {item}</li>
{/each}
</ul>
```
`{:else}` blocks can be used to render content when the list is empty.
## {#key ...}
`{#key ...}` blocks force a component or section of markup to be completely destroyed and recreated whenever the key expression changes. This is useful for triggering component re-initialization or for applying transitions when a value changes.
```svelte
<script>
let currentView = $state('view1');
</script>
{#key currentView}
<svelte:component this={currentViewComponent} />
{/key}
```
## {#await ...}
`{#await ...}` blocks handle promises and render different content based on the promise's state: pending, resolved (`:then`), or rejected (`:catch`). This is essential for handling asynchronous operations like fetching data and displaying loading states or error messages.
```svelte
<script>
let promise = fetchData(); // Function returning a Promise
</script>
{#await promise}
<p>Loading...</p>
{:then data}
<p>Data: {data}</p>
{:catch error}
<p>Error: {error.message}</p>
{/await}
```
You can omit the `:catch` or the initial pending block if not needed.
## {#snippet ...}
`{#snippet ...}` blocks define reusable chunks of markup within a component, similar to functions for markup. Snippets can accept parameters and can be rendered multiple times using `{@render snippetName(params)}`. This promotes code reuse and makes templates more organized, especially for complex UI patterns.
```svelte
<script>
let images = $state([{ src: '...', caption: 'Image 1' }, { src: '...', caption: 'Image 2' }]);
{#snippet figure(image)}
<figure>
<img src={image.src} alt={image.caption} />
<figcaption>{image.caption}</figcaption>
</figure>
{/snippet}
</script>
{#each images as image}
{@render figure(image)}
{/each}
```
Snippets can be passed as props to components, similar to slots in web components.
## {@render ...}
`{@render snippetName(params)}` tags are used to render snippets defined with `{#snippet ...}`. You call `{@render}` with the snippet's name and any parameters it expects. This is how you reuse markup defined in snippets within your templates.
```svelte
{@render figure(image)} // Renders the 'figure' snippet with 'image' data
```
Use optional chaining `{@render snippetName?.()}` for snippets that might be undefined.
## {@html ...}
`{@html expression}` tags render raw HTML strings directly into the component's markup. Use this with caution as it bypasses Svelte's escaping and can introduce security vulnerabilities if the HTML source is not trusted. Styles within `{@html}` content are not automatically scoped; use `:global` modifiers in your `<style>` block to style them.
```svelte
<script>
let htmlContent = $state('<b>Bold text</b>');
</script>
<div>{@html htmlContent}</div>
```
## {@const ...}
`{@const variable = expression}` tags define constants within markup blocks like `{#each}` or `{#if}`. These constants are scoped to the block they are defined in and are useful for calculations or values that are only needed within that block.
```svelte
{#each items as item}
{@const area = item.width * item.height}
<p>Area: {area}</p>
{/each}
```
## {@debug ...}
`{@debug var1, var2, ...}` tags are a debugging aid that logs the values of specified variables to the console whenever they change. If devtools are open, it also pauses execution, acting like a `debugger` statement. `{@debug}` without arguments acts as a general debugger that triggers on any state change.
```svelte
<script>
let name = $state('Alice');
let age = $state(30);
</script>
{@debug name, age}
<p>Name: {name}, Age: {age}</p>
```
## bind
The `bind:` directive creates two-way bindings between component state and DOM element properties or component props. For input elements, `bind:value` synchronizes the input's value with a reactive variable. Other bindings include `bind:checked` for checkboxes, `bind:group` for radio buttons and checkboxes, `bind:files` for file inputs, and `bind:this` to get a reference to a DOM element or component instance.
```svelte
<script>
let inputValue = $state('');
</script>
<input bind:value={inputValue} placeholder="Enter text" />
<p>You typed: {inputValue}</p>
```
For components, `bind:property` binds to a `$bindable` prop in the child component.
## use
The `use:` directive applies actions to DOM elements when they are mounted. Actions are functions that receive the DOM node as an argument and can return a cleanup function that runs when the element is unmounted. Actions are often used with `$effect` to manage setup and teardown logic, especially for interactions with external APIs or DOM manipulations.
```svelte
<script>
import { focusTrap } from './actions.js'; // Custom action
function myAction(node) {
console.log('Element mounted');
return () => console.log('Element unmounted');
}
</script>
<div use:myAction use:focusTrap>...</div>
```
Actions can also accept parameters: `use:action={params}`.
## transition
The `transition:` directive applies transitions to elements when they enter or leave the DOM, typically within `{#if}` blocks. Svelte provides built-in transitions like `fade`, `fly`, `slide`, `scale`, and `blur`. Transitions can be bidirectional (smoothly reversible) or unidirectional (`in:` and `out:`).
```svelte
<script>
import { fade } from 'svelte/transition';
let visible = $state(true);
</script>
<button on:click={() => visible = !visible}>Toggle</button>
{#if visible}
<div transition:fade={{ duration: 200 }}>Fades in/out</div>
{/if}
```
Transitions can be customized with parameters and custom transition functions.
## in: and out
The `in:` and `out:` directives are unidirectional transitions, similar to `transition:` but not bidirectional. `in:` transitions play when an element enters the DOM, and `out:` transitions play when it leaves. They are useful when you want separate in and out animations.
```svelte
{#if visible}
<div in:fly={{ y: 200 }} out:fade>Flies in, fades out</div>
{/if}
```
## animate
The `animate:` directive is used within keyed `{#each}` blocks to animate elements when their order changes. It uses FLIP (First, Last, Invert, Play) animation technique for smooth transitions during list reordering. Svelte provides built-in animations like `flip` and you can also create custom animation functions.
```svelte
{#each list as item (item.id)}
<li animate:flip>{item.text}</li>
{/each}
```
Animations are triggered only by reordering, not by adding or removing items.
## style
The `style:` directive provides a shorthand for setting inline styles on elements. It allows you to set multiple styles and use dynamic values. `style:propertyName={expression}` sets a specific style property. `style:propertyName` (shorthand) is equivalent to `style:propertyName={propertyName}`.
```svelte
<script>
let textColor = $state('red');
let fontSize = $state('16px');
</script>
<p style:color={textColor} style:font-size={fontSize}>Styled text</p>
```
Use `style:propertyName|important={expression}` to add `!important` to the style.
## class
Classes can be set using the `class` attribute or the `class:` directive. The `class` attribute can accept strings, objects, or arrays to dynamically set classes. Objects set classes based on truthy keys, and arrays combine truthy values. The `class:` directive `class:className={condition}` conditionally adds or removes a class based on a boolean expression.
```svelte
<script>
let isActive = $state(true);
</script>
<div class={{ active: isActive, 'text-bold': true }}>Using class object</div>
<div class:active={isActive} class:text-bold>Using class directive</div>
```
## Scoped styles
Styles defined within a `<style>` block in a `.svelte` component are automatically scoped to that component. Svelte adds a unique class to the component's elements and prefixes CSS selectors to ensure styles only apply within the component, preventing style conflicts.
```svelte
<style>
p { color: green; } /* Only applies to <p> elements in this component */
</style>
```
## Global styles
To apply styles globally, use the `:global(...)` modifier or the `:global {...}` block within a `<style>` tag. `:global(selector)` applies styles to the specified selector globally. `:global {...}` block groups multiple global style rules.
```svelte
<style>
:global(body) { margin: 0; } /* Global body style */
:global {
.global-class { /* Global class style */
color: blue;
}
}
</style>
```
## Custom properties
Svelte components support CSS custom properties (variables). You can pass custom properties as attributes to components and access them within the component's `<style>` using `var(--propertyName, fallbackValue)`. This allows for theming and customization of components.
```svelte
<Slider --track-color="blue" --thumb-size="20px" />
```
Inside `Slider.svelte`:
```svelte
<style>
.track { background-color: var(--track-color, #ccc); }
.thumb { width: var(--thumb-size, 15px); }
</style>
```
## Nested <style> elements
While only one top-level `<style>` tag is allowed per component, you can nest `<style>` tags within other elements or logic blocks. Nested `<style>` tags are inserted directly into the DOM without scoping or processing, behaving like standard HTML `<style>` tags.
```svelte
<div>
<style> /* Global style - not scoped */
div { color: red; }
</style>
</div>
```
## <svelte:boundary>
`<svelte:boundary>` elements create error boundaries, preventing errors within their children from crashing the entire application. If an error occurs within a boundary, the boundary's content is removed, and you can provide a `failed` snippet to render fallback UI or an `onerror` handler to log or handle the error.
```svelte
<svelte:boundary>
<FlakyComponent /> {/* Component that might throw errors */}
{#snippet failed(error, reset)}
<button on:click={reset}>Try again</button>
{/snippet}
</svelte:boundary>
```
## <svelte:window>
`<svelte:window>` allows you to attach event listeners directly to the `window` object and bind to window properties like `innerWidth`, `scrollY`, etc. It automatically handles adding and removing listeners when the component mounts and unmounts. It must be placed at the top level of a component.
```svelte
<svelte:window on:keydown={handleKeydown} bind:scrollY={scrollY} />
```
## <svelte:document>
`<svelte:document>` is similar to `<svelte:window>` but attaches event listeners to the `document` object. Useful for document-level events like `visibilitychange` and for binding to document properties. Must be at the top level of a component.
```svelte
<svelte:document on:visibilitychange={handleVisibilityChange} />
```
## <svelte:body>
`<svelte:body>` allows attaching event listeners to the `document.body` element. Useful for body-specific events like `mouseenter` and `mouseleave`. Must be at the top level of a component.
```svelte
<svelte:body on:mouseenter={handleMouseenter} />
```
## <svelte:head>
`<svelte:head>` allows you to insert elements into the `<head>` of the HTML document, such as `<title>`, `<meta>`, and `<link>` tags. Useful for managing document metadata from within components. Must be at the top level of a component.
```svelte
<svelte:head>
<title>My Svelte App</title>
<meta name="description" content="App description" />
</svelte:head>
```
## <svelte:element>
`<svelte:element this={tagName}>` renders a dynamic HTML element where `tagName` is a JavaScript expression that evaluates to a tag name string. Useful for rendering elements whose tag is not known at compile time, e.g., from a CMS.
```svelte
<script>
let elementTag = $state('article');
</script>
<svelte:element this={elementTag}>Dynamic element content</svelte:element>
```
## <svelte:options>
`<svelte:options>` is used to set component-specific compiler options. Options include `runes={true/false}` to force runes or legacy mode, `namespace`, `customElement`, and `css="injected"`. Must be at the top level of a component.
```svelte
<svelte:options customElement="my-component" />
```
## Stores
Stores in Svelte are objects that hold reactive values and allow components to subscribe to changes. In Svelte 5 with runes, stores are less central for component-level reactivity but remain useful for shared application state, asynchronous data, and integration with external state management libraries. You can access a store's value reactively using the `$` prefix: `$storeName`.
```svelte
<script>
import { writable } from 'svelte/store';
const count = writable(0);
</script>
<p>Count: {$count}</p>
<button on:click={() => count.update(n => n + 1)}>Increment</button>
```
`svelte/store` module provides `writable`, `readable`, `derived`, `readonly`, and `get` store utilities.
## Context
Context provides a way to share data between parent and child components without prop drilling. `setContext(key, value)` makes a value available to child components under a given key. `getContext(key)` retrieves a context value in a child component. Context is not inherently reactive; use `$state` objects in context for reactivity.
```svelte
/// file: Parent.svelte
<script>
import { setContext } from 'svelte';
let theme = $state('light');
setContext('theme', theme);
</script>
<ChildComponent />
/// file: Child.svelte
<script>
import { getContext } from 'svelte';
const theme = getContext('theme');
</script>
```
## Lifecycle hooks
Svelte 5 primarily uses `$effect` for most lifecycle needs. `onMount(callback)` runs a callback after the component is mounted. `onDestroy(callback)` runs a callback just before the component is unmounted. `tick()` returns a promise that resolves after the next DOM update. `beforeUpdate` and `afterUpdate` are deprecated in runes mode; use `$effect.pre` and `$effect` instead.
```svelte
<script>
import { onMount, onDestroy } from 'svelte';
onMount(() => { console.log('Component mounted'); });
onDestroy(() => { console.log('Component destroyed'); });
</script>
```
## Imperative component API
Svelte provides functions for programmatically managing components: `mount(Component, options)` to instantiate and mount a component, `unmount(component)` to unmount a component, `render(Component, options)` for server-side rendering, and `hydrate(Component, options)` for client-side hydration of SSR output.
```javascript
import { mount, unmount } from 'svelte';
import App from './App.svelte';
const appInstance = mount(App, { target: document.body });
// ... later ...
unmount(appInstance);
```
## TypeScript
Svelte has built-in TypeScript support. Use `<script lang="ts">` to enable TypeScript in `.svelte` files. You can use type annotations, interfaces, and generics. For more advanced TypeScript features, you might need to set up a preprocessor like `svelte-preprocess` with `vitePreprocess`. Type `$props` and `$state` variables just like regular TypeScript variables. Use `Component` and `ComponentProps` types from `svelte` for component typing.
```svelte
<script lang="ts">
let name: string = $state<string>('World');
</script>
```
---
---
description: Sveltekit code (such as routing, server endpoints, etc.)
globs: *.server.ts, +server.ts
---
Current Path Aliases:
- "@components": "./src/components"
- "@utils": "./src/utils"
- "@utils.js": "./src/utils"
- "@hooks": "./src/hooks"
- "@src": "./src"
- "@server": "./src/lib/server"
- "@api": "./src/lib/api"
- "@types": "./src/types"
- "@schemas": "./src/schemas"
- "@state": "./src/lib/state"
- "@db": "./src/lib/server/db"
Please read the file `ai-docs/sveltekit.txt` at the root of this project which includes the full sveltekit documentation if you are unsure or notice that you made a lint error while writing some code. This should help you with the correct syntax.
Below is a cheat sheet that explains all the features of Sveltekit in a concise way.
```markdown
# SvelteKit Cheat Sheet
This cheat sheet provides a quick guide to key SvelteKit features with Svelte 5 syntax (runes).
# Introduction
SvelteKit is a powerful framework built on Svelte for creating performant web applications, similar to Next.js for React or Nuxt.js for Vue. Svelte is a compiler that turns UI components into efficient JavaScript, CSS, and HTML. SvelteKit extends Svelte by providing routing, server-side rendering (SSR), build optimizations, and many other features necessary for building full-fledged applications. It handles the complex setup, allowing developers to focus on building features.
# Creating a project
To start a new SvelteKit project, use `npx sv create my-app` in your terminal. Navigate into the project directory with `cd my-app`, install dependencies using `npm install`, and start the development server with `npm run dev`. This command scaffolds a basic SvelteKit application, sets up necessary tooling like TypeScript if chosen, and launches a development server accessible at `localhost:5173`. SvelteKit uses file-based routing, where Svelte components in `src/routes` become pages in your application.
**Example commands:**
```bash
npx sv create my-app
cd my-app
npm install
npm run dev
```
# Project structure
A typical SvelteKit project organizes code into specific directories within `src`. `src/routes` is crucial, containing your application's pages and API endpoints. `src/lib` houses reusable components and utilities, with `src/lib/server` for server-only code. `static` is for assets served directly, like images or `robots.txt`. `svelte.config.js` configures SvelteKit, and `vite.config.js` configures Vite, the build tool. Understanding this structure helps in organizing and maintaining your SvelteKit application effectively.
**Example directory structure:**
```
my-project/
├── src/
│ ├── lib/
│ ├── routes/
│ └── ...
├── static/
├── package.json
├── svelte.config.js
└── vite.config.js
```
# Web standards
SvelteKit leverages standard Web APIs like Fetch, FormData, Streams, and URL APIs, promoting web development best practices. Using these platform-native APIs makes your SvelteKit skills transferable to other web development contexts. Familiarity with these APIs, especially Fetch for data fetching and Request/Response objects for handling HTTP interactions, is crucial for effective SvelteKit development. SvelteKit provides polyfills for Node.js environments during development to ensure these APIs are readily available.
**Example Fetch API usage in +server.js:**
```js
import { json } from '@sveltejs/kit';
export async function GET() {
return json({ message: 'Hello' });
}
```
# Routing
SvelteKit employs a filesystem-based router, where directories in `src/routes` define your app's URL paths. Files prefixed with `+` inside these directories, like `+page.svelte`, `+layout.svelte`, and `+server.js`, are special route files. `+page.svelte` defines a page component, `+layout.svelte` creates layouts for shared UI, and `+server.js` handles API endpoints. Layouts and error pages cascade down directories, simplifying UI structure and error handling.
**Example +page.svelte for the homepage:**
```svelte
<h1>Welcome to my SvelteKit app!</h1>
```
**Example +page.svelte in `src/routes/about`:**
```svelte
<h1>About Us</h1>
```
## +page
`+page.svelte` components define the UI for a specific route, rendered both server-side (SSR) initially and client-side (CSR) for navigation. `+page.js` (or `+page.server.js`) can export a `load` function to fetch data before rendering the page. Data from `load` is passed to `+page.svelte` as the `data` prop. `+page.server.js` runs only on the server, ideal for database access or private environment variables.
**Example +page.svelte receiving data:**
```svelte
<script lang="ts">
let { data } = $props();
</script>
<h1>{data.title}</h1>
<p>{data.content}</p>
```
**Example +page.js load function:**
```js
export async function load() {
return { title: 'My Blog Post', content: '...' };
}
```
## +error
`+error.svelte` components customize error pages for specific routes or directories. SvelteKit searches upwards in the directory structure for the closest `+error.svelte` when an error occurs. If no route-specific error page is found, a default error page is rendered. For global error customization, `src/error.html` can be created to override the fallback error page.
**Example +error.svelte:**
```svelte
<script lang="ts">
import { page } from '$app/state';
</script>
<h1>Error {page.status}: {page.error.message}</h1>
```
## +layout
`+layout.svelte` components define shared UI elements like navigation bars or footers that persist across multiple pages. Layouts are nested, creating a hierarchy where child routes inherit layouts from parent directories. `+layout.js` (or `+layout.server.js`) can provide data to layouts via `load` functions, similar to pages. Layout data is accessible to all child layouts and pages.
**Example +layout.svelte with a navbar:**
```svelte
<script lang="ts">
let { children } = $props();
</script>
<nav>...</nav>
{@render children()}
```
**Example +layout.js load function:**
```js
export async function load() {
return { navItems: [...] };
}
```
## +server
`+server.js` files define API endpoints, handling HTTP requests like GET, POST, etc. They export functions corresponding to HTTP methods (e.g., `GET`, `POST`) that receive a `RequestEvent` and return a `Response`. `+server.js` can coexist with `+page` files in the same directory, enabling content negotiation based on the `Accept` header. Use `error`, `redirect`, and `json` helpers from `@sveltejs/kit` for convenience in server routes.
**Example +server.js GET endpoint:**
```js
import { json } from '@sveltejs/kit';
export async function GET() {
return json({ message: 'Hello from API' });
}
```
## $types
SvelteKit generates `$types.d.ts` for type safety in route files when using TypeScript. Import types like `PageData`, `LayoutData`, `PageLoad`, `LayoutLoad`, etc., from `$types` to type your `load` functions and component `data` props. Using these types ensures type checking and improves code maintainability. IDEs with Svelte language tools can often infer these types, reducing the need for explicit type annotations.
**Example typing `data` prop in +page.svelte:**
```svelte
<script lang="ts">
/** @type {import('./$types').PageData} */
let { data } = $props();
</script>
```
# Loading data
`load` functions in `+page.js`, `+page.server.js`, `+layout.js`, and `+layout.server.js` are used to fetch data for pages and layouts. `+page.js` and `+layout.js` are universal, running both server and client-side, while `+page.server.js` and `+layout.server.js` are server-only. Data returned from `load` functions becomes the `data` prop in corresponding `+page.svelte` and `+layout.svelte` components. Server `load` functions are ideal for secure data fetching or database interactions.
**Example +page.server.js load function fetching data:**
```js
export async function load() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return { data };
}
```
## Page data
`+page.js` or `+page.server.js` files export `load` functions to provide data to `+page.svelte` components. The return value of `load` is accessible in `+page.svelte` via the `data` prop. Use `PageLoad` or `PageServerLoad` types from `$types` to type your `load` functions. Server `load` functions are suitable for operations requiring server-side context or security.
**Example +page.svelte using page data:**
```svelte
<script lang="ts">
let { data } = $props();
</script>
<p>Data: {JSON.stringify(data)}</p>
```
## Layout data
`+layout.js` or `+layout.server.js` files provide data to `+layout.svelte` components and their children. Layout `load` data is accessible in child layouts and pages. Use `LayoutLoad` or `LayoutServerLoad` types from `$types` for type safety. Layout data is useful for shared resources like navigation items or user settings.
**Example +layout.svelte using layout data:**
```svelte
<script lang="ts">
let { data, children } = $props();
</script>
<nav>...</nav>
{@render children()}
```
## page.data
`page.data` in `+layout.svelte` allows accessing data from child pages or layouts. This is useful for parent layouts to be aware of child route data, for example, to set the page title dynamically based on page-specific data. Access `page.data` through the `page` store from `$app/state`.
**Example +layout.svelte accessing page.data for title:**
```svelte
<script lang="ts">
import { page } from '$app/state';
</script>
<svelte:head>
<title>{page.data.title || 'My App'}</title>
</svelte:head>
```
## Universal vs server
Universal `load` functions (`+page.js`, `+layout.js`) run on both server and client, while server `load` functions (`+page.server.js`, `+layout.server.js`) run only server-side. Server `load` functions have access to server-specific context like cookies and private environment variables. Universal `load` functions are suitable for fetching public APIs, while server `load` functions are better for secure data access.
## Using URL data
`load` functions receive `url`, `route`, and `params` properties in the event object, providing access to URL information. `url` is a `URL` object, `route` contains route information, and `params` holds route parameters. Use these properties to dynamically fetch data based on the current URL or route parameters.
**Example +page.js load function using URL params:**
```js
export async function load({ params }) {
const slug = params.slug;
// Fetch data based on slug
return { post: { slug } };
}
```
## Making fetch requests
The `fetch` function provided in `load` functions is enhanced for SvelteKit. It handles relative URLs, credentialed requests, and optimizes for server-side rendering and hydration. Use this `fetch` for all data fetching within `load` functions to leverage these SvelteKit enhancements.
**Example +page.js load function using fetch:**
```js
export async function load({ fetch }) {
const res = await fetch('/api/data');
const data = await res.json();
return { apiData: data };
}
```
## Cookies
Server `load` functions have access to `cookies` object from the event, allowing you to get and set cookies. Use `cookies.get()` to read cookies and `cookies.set()` to set them. Cookies are useful for session management and storing user-specific preferences.
**Example +layout.server.js load function using cookies:**
```js
export async function load({ cookies }) {
const sessionId = cookies.get('sessionid');
return { sessionId };
}
```
## Headers
`setHeaders` function in `load` functions allows setting response headers, useful for caching control. Headers set via `setHeaders` are applied during server-side rendering. Use `setHeaders` to control caching behavior for pages and layouts.
**Example +page.js load function setting cache headers:**
```js
export async function load({ fetch, setHeaders }) {
const response = await fetch('/api/products');
setHeaders({
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
```
## Using parent data
`await parent()` in `load` functions allows accessing data from parent layout `load` functions. This enables data composition and avoids redundant data fetching. Be mindful of potential waterfalls when using `await parent()`, and fetch independent data concurrently if possible.
**Example +page.js load function using parent data:**
```js
export async function load({ parent }) {
const parentData = await parent();
return { ...parentData, pageSpecificData: '...' };
}
```
## Errors
Use the `error` helper from `@sveltejs/kit` to throw expected errors with HTTP status codes in `load` functions. This triggers rendering of the nearest `+error.svelte` component. For unexpected errors, SvelteKit invokes `handleError` hook and renders a generic error response.
**Example +page.server.js load function throwing an error:**
```js
import { error } from '@sveltejs/kit';
export async function load({ params }) {
if (!params.id) {
error(400, 'Missing ID');
}
return {};
}
```
## Redirects
Use the `redirect` helper from `@sveltejs/kit` to redirect users to different pages from `load` functions or actions. Specify the redirect status code (3xx) and the target URL. `redirect` throws an exception that SvelteKit catches to perform the redirection.
**Example +layout.server.js load function redirecting:**
```js
import { redirect } from '@sveltejs/kit';
export async function load({ locals }) {
if (!locals.user) {
redirect(303, '/login');
}
return {};
}
```
## Streaming with promises
Server `load` functions can return promises, enabling streaming of data to the browser as promises resolve. This is useful for non-critical data, improving initial page load time. Handle promise rejections properly to avoid server crashes.
**Example +page.server.js load function streaming comments:**
```js
export async function load({ params }) {
return {
post: loadPost(params.slug),
comments: loadComments(params.slug) // Promise for comments
};
}
```
## Parallel loading
SvelteKit runs all `load` functions concurrently, avoiding request waterfalls and improving performance. During client-side navigation, server `load` functions are grouped into a single server request.
## Rerunning load functions
SvelteKit tracks dependencies of `load` functions (params, URL, `fetch` calls) to rerun them only when necessary during navigation. Use `invalidate(url)` or `invalidateAll()` from `$app/navigation` to manually trigger `load` function reruns.
**Example +page.svelte invalidating load function:**
```svelte
<script lang="ts">
import { invalidate } from '$app/navigation';
function updateData() {
invalidate('/api/data');
}
</script>
<button on:click={updateData}>Update Data</button>
```
# Form actions
Form actions in `+page.server.js` handle form submissions using `<form>` elements. Define actions within `export const actions = { ... }`. Default actions are invoked for forms without `action` attributes, while named actions are accessed via `action="?/actionName"`. Actions receive form data and can return data, validation errors, or redirects.
**Example +page.server.js with a default action:**
```js
export const actions = {
default: async ({ request }) => {
const formData = await request.formData();
// Process form data
return { success: true };
}
};
```
**Example +page.svelte form using default action:**
```svelte
<form method="POST">
<button>Submit</button>
</form>
```
## Default actions
A `default` action in `+page.server.js` handles form submissions from the page itself. Forms on the page without an `action` attribute will invoke the `default` action upon submission.
**Example +page.server.js default action:**
```js
export const actions = {
default: async () => {
// Handle default form submission
return { message: 'Default action executed' };
}
};
```
## Named actions
Named actions in `+page.server.js` allow multiple form handlers on a single page. Invoke named actions by adding `action="?/actionName"` to the `<form>` or `<button formaction="?/actionName">`.
**Example +page.server.js with named actions:**
```js
export const actions = {
login: async () => { /* ... */ },
register: async () => { /* ... */ }
};
```
**Example +page.svelte form using named action:**
```svelte
<form method="POST" action="?/login">
<button>Login</button>
</form>
```
## Anatomy of an action
Actions receive a `RequestEvent` object, allowing access to form data via `request.formData()`. Actions can return data, which becomes available in `+page.svelte` as the `form` prop. Use actions to handle form submissions, validation, and server-side logic.
**Example +page.server.js action returning data:**
```js
export const actions = {
submit: async ({ request }) => {
const formData = await request.formData();
const name = formData.get('name');
return { name };
}
};
```
## Validation errors
Use the `fail` function from `@sveltejs/kit` to return validation errors from actions. `fail(statusCode, data)` returns an `ActionFailure` with a status code and error data. Error data is available in `+page.svelte` via the `form` prop, allowing you to display validation messages.
**Example +page.server.js action with validation fail:**
```js
import { fail } from '@sveltejs/kit';
export const actions = {
submit: async ({ request }) => {
const formData = await request.formData();
const email = formData.get('email');
if (!email) {
return fail(400, { email, missing: true });
}
return { success: true };
}
};
```
## Redirects
Redirects from actions work similarly to `load` functions, using the `redirect` helper. Redirects from actions are useful after successful form submissions, directing users to the next appropriate page.
**Example +page.server.js action redirecting after success:**
```js
import { redirect } from '@sveltejs/kit';
export const actions = {
submit: async () => {
// ... form processing ...
redirect(303, '/dashboard');
}
};
```
## Loading data
After an action runs, `load` functions are re-run, ensuring data is updated after form submissions. This keeps the page data consistent with the server-side changes made by the action.
## Progressive enhancement
SvelteKit form actions support progressive enhancement, working even without client-side JavaScript. Use `use:enhance` action in `+page.svelte` to enhance forms with JavaScript for a better user experience without full page reloads.
**Example +page.svelte form with `use:enhance`:**
```svelte
<script lang="ts">
import { enhance } from '$app/forms';
</script>
<form method="POST" use:enhance>
...
</form>
```
## use:enhance
`use:enhance` action progressively enhances forms, handling submissions via JavaScript without full page reloads. It updates the `form` prop, `page.form`, and `page.status` on form responses. It can be customized with a `SubmitFunction` to control loading states and response handling.
**Example +page.svelte form with custom `use:enhance`:**
```svelte
<script lang="ts">
import { enhance } from '$app/forms';
function handleSubmit() {
return async ({ result }) => {
// Custom handling of form result
};
}
</script>
<form method="POST" use:enhance={handleSubmit}>
...
</form>
```
## Custom event listener
Progressive enhancement can also be implemented with custom event listeners on `<form>`, without `use:enhance`. This provides more granular control over form submission and response handling. Remember to `deserialize` the response from the server.
**Example +page.svelte form with custom submit handler:**
```svelte
<script lang="ts">
import { deserialize, applyAction } from '$app/forms';
async function handleSubmit(event) {
event.preventDefault();
const response = await fetch(event.target.action, { method: 'POST', body: new FormData(event.target) });
const result = deserialize(await response.text());
applyAction(result);
}
</script>
<form method="POST" onsubmit={handleSubmit}>
...
</form>
```
## Alternatives
While form actions are preferred, `+server.js` files can also be used to create JSON APIs for data submission. Choose form actions for progressively enhanced forms and `+server.js` for general API endpoints.
## GET vs POST
Use `method="POST"` for form actions. `method="GET"` (or no method) in `<form>` triggers client-side navigation instead of form actions, similar to `<a>` elements. `method="GET"` forms are useful for search inputs or navigation-based forms.
# Page options
Page options control rendering behavior (SSR, CSR, prerendering) and are exported from `+page.js`, `+page.server.js`, `+layout.js`, or `+layout.server.js`. Options cascade down the route hierarchy, with child routes overriding parent options. Common options include `prerender`, `ssr`, `csr`, and `trailingSlash`.
## prerender
`prerender = true` in route files prerenders routes to static HTML at build time. `prerender = false` disables prerendering for specific routes. `prerender = 'auto'` (default) prerenders where possible but includes routes in the server manifest for dynamic SSR if needed. Prerendering improves performance for static content.
**Example +page.js enabling prerender:**
```js
export const prerender = true;
```
## entries
`entries` function in dynamic routes (`[slug]`) specifies paths to prerender for dynamic segments. It returns an array of parameter objects for prerendering specific dynamic routes.
**Example +page.server.js with entries for prerendering dynamic routes:**
```js
export const entries = () => {
return [{ slug: 'post-1' }, { slug: 'post-2' }];
};
export const prerender = true;
```
## ssr
`ssr = false` in route files disables server-side rendering, forcing client-side rendering only. Useful for pages relying on browser-specific APIs. Setting `ssr = false` in the root layout turns the entire app into a single-page application (SPA).
**Example +page.js disabling SSR:**
```js
export const ssr = false;
```
## csr
`csr = false` disables client-side rendering (hydration), creating a static HTML page with no JavaScript. Useful for purely static content like blog posts. No interactivity or client-side routing is available with `csr = false`.
**Example +page.js disabling CSR:**
```js
export const csr = false;
```
## trailingSlash
`trailingSlash` option controls trailing slash behavior in URLs. `'never'` (default) removes trailing slashes, `'always'` adds them, and `'ignore'` allows both with and without trailing slashes.
**Example +layout.js enforcing trailing slashes:**
```js
export const trailingSlash = 'always';
```
# State management
Avoid shared state on the server to prevent data leaks between users. `load` functions should be pure, without side effects. Use Svelte's context API for component-specific state management. Component and page state is preserved during navigation. URL search parameters are suitable for state that should survive reloads and affect SSR.
## Avoid shared state on the server
Do not use global variables to store user-specific data on the server, as servers are stateless and shared across users. Store user data in databases or sessions, accessed per request, to prevent data leaks.
## No side-effects in load
`load` functions should be pure functions, returning data without side effects like modifying global state or stores. Side effects in `load` functions can lead to unpredictable behavior, especially in server-rendered applications.
## Using state and stores with context
Use Svelte's context API (`setContext`, `getContext`) for component-specific state management, especially for server-rendered apps. Context avoids global state issues and keeps state localized within component trees.
**Example +layout.svelte setting context:**
```svelte
<script lang="ts">
import { setContext } from 'svelte';
setContext('user', () => $state({ name: 'User' }));
</script>
```
**Example +page.svelte getting context:**
```svelte
<script lang="ts">
import { getContext } from 'svelte';
const user = getContext('user');
</script>
<p>Welcome {$user().name}</p>
```
## Component and page state is preserved
SvelteKit reuses components during navigation, preserving their internal state. Use reactive declarations (`$derived`) to update component state based on props or data changes. Use `{#key ...}` block to force component remounting on navigation if needed.
**Example +page.svelte using reactive declarations:**
```svelte
<script lang="ts">
let { data } = $props();
let wordCount = $derived(data.content.split(' ').length);
</script>
```
## Storing state in the URL
URL search parameters are ideal for state that should persist across reloads and influence SSR, like filters or sorting. Access search parameters in `load` functions via `url.searchParams` and in components via `page.url.searchParams`.
## Storing ephemeral state in snapshots
Snapshots preserve temporary UI state (e.g., form input values) across navigations. Export a `snapshot` object with `capture` and `restore` methods from `+page.svelte` or `+layout.svelte` to manage snapshot state.
**Example +page.svelte using snapshot:**
```svelte
<script lang="ts">
let comment = $state('');
export const snapshot = {
capture: () => comment,
restore: (value) => comment = value
};
</script>
```
# Building your app
`vite build` command builds your SvelteKit app for production. Build process includes Vite optimizing server and client code, service worker bundling, and prerendering. Use `building` from `$app/environment` to conditionally execute code that should not run during build time.
**Example conditional code execution during build:**
```js
import { building } from '$app/environment';
if (!building) {
// Code to run only when not building
}
```
## Preview your app
`vite preview` command serves the production build locally after building. Preview is useful for testing the built application before deployment, but may not perfectly replicate the deployed environment.
# Adapters
Adapters are plugins that adapt the built SvelteKit app for specific deployment platforms (e.g., Netlify, Vercel, Cloudflare). Specify the adapter in `svelte.config.js`. Adapters handle platform-specific configurations and output formats.
**Example svelte.config.js using an adapter:**
```js
import adapter from '@sveltejs/adapter-auto';
export default {
kit: {
adapter: adapter()
}
};
```
## Platform-specific context
Adapters may provide platform-specific context data (e.g., Cloudflare Workers `env` object) accessible in hooks and server routes via `event.platform`. Consult adapter documentation for platform-specific context details.
# Single-page apps
SvelteKit apps can be configured as SPAs by setting `ssr = false` in the root layout. Use `@sveltejs/adapter-static` with a fallback page for SPA deployments.
**Example svelte.config.js for SPA with adapter-static:**
```js
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({ fallback: '200.html' })
}
};
```
# Advanced routing
## Rest parameters
Rest parameters (`[...param]`) match multiple route segments, useful for dynamic paths of unknown depth. Rest parameters are greedy and capture all remaining segments.
**Example route with rest parameter: `src/routes/blog/[...slug]/+page.svelte`**
## Optional parameters
Optional parameters (`[[param]]`) make route parameters optional. `[[lang]]/home` matches both `/home` and `/en/home`. Optional parameters cannot follow rest parameters.
**Example route with optional parameter: `src/routes/[[lang]]/about/+page.svelte`**
## Matching
Parameter matchers in `src/params` validate route parameters. Create matcher functions in `src/params` and reference them in route parameters like `[param=matcher]`.
**Example param matcher `src/params/fruit.js`:**
```js
export function match(param) {
return ['apple', 'orange'].includes(param);
}
```
**Example route using matcher: `src/routes/fruits/[fruit=fruit]/+page.svelte`**
## Sorting
SvelteKit sorts routes based on specificity, with more specific routes having higher priority. Specific routes, matchers, and non-optional parameters have higher priority than less specific routes.
## Encoding
Use hexadecimal escape sequences (`[x+nn]`) for characters not allowed in filenames within route paths. Unicode escape sequences (`[u+nnnn]`) can also be used.
**Example route with encoded character: `src/routes/smileys/[x+3a]-[x+29]/+page.svelte` (for `/smileys/:-)` route)**
## Advanced layouts
Layout groups `(group)` group routes without affecting URL paths, useful for different layouts within an app. Layout breakouts (`+layout@`) allow pages or layouts to break out of the layout hierarchy, resetting to a specific parent layout.
**Example layout groups:**
```
src/routes/
├── (app)/
│ └── dashboard/+page.svelte
├── (marketing)/
│ └── about/+page.svelte
└── +layout.svelte // Root layout
```
# Hooks
Hooks are app-wide functions in `src/hooks.server.js`, `src/hooks.client.js`, and `src/hooks.js` for customizing SvelteKit behavior. Server hooks (`handle`, `locals`, `handleFetch`) run on the server. Client hooks (`handleError`) run on the client. Universal hooks (`reroute`, `transport`) run on both.
## Server hooks
Server hooks in `src/hooks.server.js` customize server-side request handling. `handle` hook intercepts every request, `locals` adds custom data to requests, and `handleFetch` modifies `fetch` requests.
**Example src/hooks.server.js handle hook:**
```js
export async function handle({ event, resolve }) {
const response = await resolve(event);
response.headers.set('x-custom-header', 'potato');
return response;
}
```
## Shared hooks
`handleError` hook in `src/hooks.js`, `src/hooks.server.js`, or `src/hooks.client.js` handles unexpected errors during loading or rendering. `init` hook in `src/hooks.js`, `src/hooks.server.js`, or `src/hooks.client.js` runs once on server start or client app initialization.
**Example src/hooks.server.js handleError hook:**
```js
export async function handleError({ error, event }) {
console.error('Unexpected error:', error);
return { message: 'Something went wrong!' };
}
```
## Universal hooks
Universal hooks in `src/hooks.js` run on both server and client. `reroute` hook modifies URL-to-route translation. `transport` hook handles custom data types across server-client boundary.
**Example src/hooks.js reroute hook:**
```js
export function reroute({ url }) {
if (url.pathname === '/ueber-uns') {
return '/about';
}
}
```
# Errors
SvelteKit distinguishes between expected errors (thrown with `error()`) and unexpected errors. Expected errors render `+error.svelte` pages. Unexpected errors are handled by `handleError` hook and render a fallback error page.
## Expected errors
Expected errors are created using `error(status, message)` from `@sveltejs/kit`. They trigger rendering of `+error.svelte` components and set the HTTP status code.
**Example throwing expected error in +page.server.js load:**
```js
import { error } from '@sveltejs/kit';
export async function load() {
error(404, 'Page not found');
}
```
## Unexpected errors
Unexpected errors are exceptions not created by `error()`. They are handled by `handleError` hook, logged, and a generic error response is shown to users.
## Responses
For errors in `handle` or `+server.js`, SvelteKit responds with a fallback error page or JSON error, based on `Accept` headers. Customize fallback error page with `src/error.html`. Errors in `load` functions render `+error.svelte` components.
## Type safety
Customize error object shape in TypeScript by declaring `App.Error` interface in `src/app.d.ts`.
**Example src/app.d.ts customizing error type:**
```ts
declare global {
namespace App {
interface Error {
code: string;
}
}
}
```
# Link options
`data-sveltekit-*` attributes on `<a>` elements customize link behavior. `data-sveltekit-preload-data` and `data-sveltekit-preload-code` control preloading. `data-sveltekit-reload` forces full-page reload. `data-sveltekit-replacestate` replaces history entry. `data-sveltekit-keepfocus` preserves focus. `data-sveltekit-noscroll` disables scrolling.
## data-sveltekit-preload-data
`data-sveltekit-preload-data="hover"` (default) preloads data on hover. `data-sveltekit-preload-data="tap"` preloads data on tap/click. Preloading improves navigation speed.
**Example disabling preload data for a specific link:**
```html
<a href="/slow-page" data-sveltekit-preload-data="false">Slow Page</a>
```
## data-sveltekit-preload-code
`data-sveltekit-preload-code` controls code preloading. `"eager"` preloads immediately, `"viewport"` preloads when in viewport, `"hover"` and `"tap"` preload code on hover/tap.
**Example preloading code on hover:**
```html
<a href="/future-page" data-sveltekit-preload-code="hover">Future Page</a>
```
## data-sveltekit-reload
`data-sveltekit-reload` forces a full-page reload when the link is clicked, bypassing client-side routing. Useful for links to external parts of the application or pages that require a full reload.
**Example forcing full reload for a link:**
```html
<a href="/legacy-page" data-sveltekit-reload>Legacy Page</a>
```
## data-sveltekit-replacestate
`data-sveltekit-replacestate` replaces the current history entry instead of creating a new one during navigation. Useful for actions that shouldn't create back-history entries.
**Example replacing history state for a link:**
```html
<a href="/dashboard" data-sveltekit-replacestate>Dashboard</a>
```
## data-sveltekit-keepfocus
`data-sveltekit-keepfocus` prevents focus reset after navigation, preserving focus on the currently focused element. Use cautiously, especially on links, as it can be confusing for accessibility.
**Example keeping focus on a form:**
```html
<form data-sveltekit-keepfocus>
<input type="text" name="search">
</form>
```
## data-sveltekit-noscroll
`data-sveltekit-noscroll` prevents scrolling to the top of the page after navigation. Useful for preserving scroll position in specific scenarios.
**Example disabling scroll reset for a link:**
```html
<a href="/long-page" data-sveltekit-noscroll>Long Page</a>
```
# Service workers
Service workers in `src/service-worker.js` act as proxy servers, enabling offline support and caching. SvelteKit automatically bundles and registers service workers. Use `$service-worker` module in service workers for access to build assets and version info.
**Example basic service worker `src/service-worker.js`:**
```js
import { build, files, version } from '$service-worker';
const ASSETS = [...build, ...files];
const CACHE = `cache-${version}`;
self.addEventListener('install', event => {
event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(ASSETS)));
});
```
# Server-only modules
Server-only modules prevent accidental import of server-side code into client-side code. Modules in `$lib/server` or with `.server` extension are server-only. SvelteKit errors if server-only code is imported into public-facing code.
**Example server-only module `src/lib/server/secrets.js`:**
```js
export const API_KEY = 'secret-key';
```
# Snapshots
Snapshots preserve ephemeral DOM state across navigations. Export `snapshot` object from `+page.svelte` or `+layout.svelte` with `capture` and `restore` methods to manage snapshot state.
**Example +page.svelte using snapshot for comment textarea:**
```svelte
<script lang="ts">
let comment = $state('');
export const snapshot = {
capture: () => comment,
restore: (value) => comment = value
};
</script>
<textarea bind:value={comment}></textarea>
```
# Shallow routing
Shallow routing uses `pushState` and `replaceState` from `$app/navigation` to create history entries without full navigation. Useful for modals or UI states that should be dismissible with back/forward navigation.
**Example +page.svelte using shallow routing for a modal:**
```svelte
<script lang="ts">
import { pushState } from '$app/navigation';
import { page } from '$app/state';
function showModal() {
pushState('', { showModal: true });
}
</script>
{#if page.state.showModal}
<Modal close={() => history.back()} />
{/if}
```
# Auth
Auth in SvelteKit involves authentication (verifying user identity) and authorization (determining user permissions). Sessions or tokens (JWT) are common authentication methods. Auth cookies can be checked in server hooks, and user information can be stored in `locals`.
# Images
Optimize images for performance by using appropriate formats (`.avif`, `.webp`), sizes, and caching. Vite handles basic asset processing. `@sveltejs/enhanced-img` plugin provides advanced image optimization. CDNs offer dynamic image optimization.
**Example using `@sveltejs/enhanced-img` in +page.svelte:**
```svelte
<enhanced:img src="./image.jpg" alt="My Image" />
```
# Accessibility
SvelteKit provides built-in accessibility features like route announcements and focus management. Ensure each page has a unique `<title>` in `<svelte:head>`. Use `lang` attribute in `src/app.html` for document language.
**Example +page.svelte with title for accessibility:**
```svelte
<svelte:head>
<title>My Accessible Page</title>
</svelte:head>
```
# SEO
SvelteKit is SEO-friendly with SSR by default. Optimize SEO by providing `<title>` and `<meta name="description">` in `<svelte:head>`. Create sitemaps dynamically using `+server.js` endpoints.
**Example +page.svelte with title and description for SEO:**
```svelte
<svelte:head>
<title>My SEO Optimized Page</title>
<meta name="description" content="Description of my page" />
</svelte:head>
```
# @sveltejs/kit
`@sveltejs/kit` module provides core SvelteKit functionalities, including `error`, `redirect`, `json`, `fail`, and types for hooks, actions, and events.
# @sveltejs/kit/hooks
`@sveltejs/kit/hooks` module provides `sequence` helper for chaining `handle` hooks.
**Example using `sequence` in src/hooks.server.js:**
```js
import { sequence } from '@sveltejs/kit/hooks';
export const handle = sequence(handler1, handler2);
```
# $app/environment
`$app/environment` module provides environment variables: `browser`, `building`, `dev`, and `version`.
**Example using `$app/environment` in +page.svelte:**
```svelte
<script lang="ts">
import { dev } from '$app/environment';
console.log('Dev mode:', dev);
</script>
```
# $app/forms
`$app/forms` module provides `applyAction`, `deserialize`, and `enhance` for form handling.
**Example using `enhance` in +page.svelte:**
```svelte
<script lang="ts">
import { enhance } from '$app/forms';
</script>
<form method="POST" use:enhance>...</form>
```
# $app/navigation
`$app/navigation` module provides navigation functions: `goto`, `invalidate`, `invalidateAll`, `beforeNavigate`, `afterNavigate`, `pushState`, `replaceState`, `preloadData`, `preloadCode`.
**Example using `goto` in +page.svelte:**
```svelte
<script lang="ts">
import { goto } from '$app/navigation';
function navigateToAbout() {
goto('/about');
}
</script>
<button on:click={navigateToAbout}>Go to About</button>
```
# $app/paths
`$app/paths` module provides path variables: `base`, `assets`, and `resolveRoute`.
**Example using `base` in +page.svelte:**
```svelte
<script lang="ts">
import { base } from '$app/paths';
</script>
<a href="{base}/about">About</a>
```
# $app/server
`$app/server` module provides `read` function for reading assets from the filesystem (server-only).
# $app/state
`$app/state` module provides reactive state objects: `page`, `navigating`, and `updated`.
**Example using `page` in +layout.svelte:**
```svelte
<script lang="ts">
import { page } from '$app/state';
</script>
<p>Current path: {$page.url.pathname}</p>
```
# $app/stores
`$app/stores` module provides store-based equivalents of `$app/state` (legacy, use `$app/state` in Svelte 5).
# $env
`$env` modules provide access to environment variables: `$env/dynamic/private`, `$env/dynamic/public`, `$env/static/private`, `$env/static/public`.
# $lib
`$lib` alias provides access to code in `src/lib` directory.
# $service-worker
`$service-worker` module (service worker context only) provides service worker-specific variables: `base`, `build`, `files`, `prerendered`, `version`.
```markdown
## Configuration
`svelte.config.js` at the project root configures SvelteKit. It includes options for the Svelte compiler, SvelteKit-specific settings under `kit`, preprocessors, and Vite plugin options. Key configurations include `kit.adapter` for deployment, `kit.alias` for import aliases, `kit.csp` for Content Security Policy, `kit.prerender` for static site generation, and `kit.serviceWorker` for service worker settings.
**Example svelte.config.js with adapter and alias:**
```js
import adapter from '@sveltejs/adapter-auto';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter(),
alias: {
'$components': 'src/lib/components'
}
}
};
export default config;
```
## @sveltejs/kit Module Details
The `@sveltejs/kit` module provides essential functions and types for SvelteKit development. Key exports include:
- **`Server`**: Class for creating a SvelteKit server instance.
- **`VERSION`**: Current SvelteKit version string.
- **`error(status, body)`**: Function to throw expected HTTP errors.
- **`fail(status, data)`**: Function to create action failures with data.
- **`isActionFailure(e)`**: Type guard to check for action failures.
- **`isHttpError(e, status)`**: Type guard to check for HTTP errors.
- **`isRedirect(e)`**: Type guard to check for redirects.
- **`json(data, init)`**: Function to create JSON responses.
- **`redirect(status, location)`**: Function to throw redirects.
- **`text(body, init)`**: Function to create text responses.
- **`Action`**: Type for form action functions.
- **`ActionFailure`**: Interface for action failure objects.
- **`ActionResult`**: Type for action result objects.
- **`Actions`**: Type for `export const actions` object.
- **`Adapter`**: Interface for SvelteKit adapters.
- **`AfterNavigate`**: Interface for `afterNavigate` callback argument.
- **`BeforeNavigate`**: Interface for `beforeNavigate` callback argument.
- **`Builder`**: Interface for adapter builder object.
- **`ClientInit`**: Type for client-side `init` hook.
- **`Config`**: Type for `svelte.config.js` configuration object.
- **`Cookies`**: Interface for cookie API in `RequestEvent`.
- **`Emulator`**: Interface for adapter emulator object.
- **`Handle`**: Type for `handle` server hook.
- **`HandleClientError`**: Type for `handleError` client hook.
- **`HandleFetch`**: Type for `handleFetch` server hook.
- **`HandleServerError`**: Type for `handleError` server hook.
- **`HttpError`**: Interface for HTTP error objects.
- **`KitConfig`**: Type for `kit` property in `svelte.config.js`.
- **`Load`**: Generic type for `load` functions.
- **`LoadEvent`**: Interface for `load` function event argument.
- **`Navigation`**: Interface for navigation objects.
- **`NavigationEvent`**: Interface for navigation event arguments.
- **`NavigationTarget`**: Interface for navigation target information.
- **`NavigationType`**: Type for navigation types.
- **`OnNavigate`**: Interface for `onNavigate` callback argument.
- **`Page`**: Interface for `page` reactive object and `$page` store.
- **`ParamMatcher`**: Type for parameter matcher functions.
- **`PrerenderOption`**: Type for prerender options (`true`, `false`, `'auto'`).
- **`Redirect`**: Interface for redirect objects.
- **`RequestEvent`**: Interface for `+server.js` and `load` function event argument.
- **`RequestHandler`**: Type for `+server.js` request handler functions.
- **`Reroute`**: Type for `reroute` universal hook.
- **`ResolveOptions`**: Interface for `resolve` function options in `handle` hook.
- **`RouteDefinition`**: Interface for route definition objects.
- **`SSRManifest`**: Interface for server-side rendering manifest.
- **`ServerInit`**: Type for server-side `init` hook.
- **`ServerInitOptions`**: Interface for server-side `init` hook options.
- **`ServerLoad`**: Generic type for server `load` functions.
- **`ServerLoadEvent`**: Interface for server `load` function event argument.
- **`Snapshot`**: Interface for `snapshot` object in components.
- **`SubmitFunction`**: Type for `use:enhance` submit function.
- **`Transport`**: Type for `transport` universal hook.
- **`Transporter`**: Interface for transporter object in `transport` hook.
## @sveltejs/kit/hooks Module Details
The `@sveltejs/kit/hooks` module currently only exports the `sequence` helper function, used for chaining multiple `handle` hooks in `src/hooks.server.js`.
## @sveltejs/kit/node/polyfills Module Details
The `@sveltejs/kit/node/polyfills` module provides `installPolyfills` function, which makes various Web APIs like `crypto` and `File` available as globals in Node.js environments.
## @sveltejs/kit/node Module Details
The `@sveltejs/kit/node` module provides functions for Node.js environments:
- **`createReadableStream(file)`**: Converts a file on disk to a readable stream.
- **`getRequest({ request, base, bodySizeLimit })`**: Creates a `Request` object from Node.js `IncomingMessage`.
- **`setResponse(res, response)`**: Sets a Node.js `ServerResponse` based on a SvelteKit `Response`.
## @sveltejs/kit/vite Module Details
The `@sveltejs/kit/vite` module exports the `sveltekit()` function, which returns the SvelteKit Vite plugins. This plugin is essential for integrating SvelteKit into the Vite build process.
## $app/environment Module Details
The `$app/environment` module provides environment-related constants:
- **`browser`**: `true` if running in the browser.
- **`building`**: `true` during build and prerendering.
- **`dev`**: `true` if the dev server is running.
- **`version`**: Application version from `config.kit.version.name`.
**Example using `$app/environment` in a component:**
```svelte
<script lang="ts">
import { browser, dev } from '$app/environment';
console.log('Running in browser:', browser);
console.log('Dev mode:', dev);
</script>
```
## $app/forms Module Details
The `$app/forms` module provides functions for form handling:
- **`applyAction(result)`**: Updates page `form` prop and handles action results.
- **`deserialize(result)`**: Deserializes form submission responses.
- **`enhance(form_element, submit)`**: Progressively enhances forms.
## $app/navigation Module Details
The `$app/navigation` module provides functions for client-side navigation:
- **`afterNavigate(callback)`**: Runs callback after navigation completes.
- **`beforeNavigate(callback)`**: Runs callback before navigation starts (can cancel navigation).
- **`disableScrollHandling()`**: Disables SvelteKit's scroll handling.
- **`goto(url, opts)`**: Programmatically navigates to a URL.
- **`invalidate(resource)`**: Invalidates `load` functions based on resource dependency.
- **`invalidateAll()`**: Invalidates all `load` functions.
- **`onNavigate(callback)`**: Runs callback before navigation (can delay navigation).
- **`preloadCode(pathname)`**: Programmatically preloads code for a route.
- **`preloadData(href)`**: Programmatically preloads data for a route.
- **`pushState(url, state)`**: Creates a new history entry with page state (shallow routing).
- **`replaceState(url, state)`**: Replaces current history entry with page state (shallow routing).
## $app/paths Module Details
The `$app/paths` module provides path-related variables and functions:
- **`assets`**: Absolute path to assets directory.
- **`base`**: Base path of the application.
- **`resolveRoute(id, params)`**: Resolves a route ID with parameters to a pathname.
## $app/server Module Details
The `$app/server` module provides server-only functionalities:
- **`read(asset)`**: Reads the content of an asset from the filesystem.
## $app/state Module Details
The `$app/state` module provides reactive state objects (Svelte 5 runes):
- **`navigating`**: Reactive object representing in-progress navigation.
- **`page`**: Reactive object with current page information (`url`, `params`, `data`, `error`, `state`, `form`).
- **`updated`**: Reactive object indicating app updates (`current`, `check()`).
## $app/stores Module Details
The `$app/stores` module provides store-based equivalents of `$app/state` (legacy, use `$app/state` in Svelte 5 for runes).
## $env Modules Details
The `$env` modules provide access to environment variables:
- **`$env/dynamic/private`**: Dynamic private environment variables (server-only).
- **`$env/dynamic/public`**: Dynamic public environment variables (client and server).
- **`$env/static/private`**: Static private environment variables (server-only, build-time).
- **`$env/static/public`**: Static public environment variables (client and server, build-time).
## $lib Module Details
The `@lib` alias provides convenient access to files in the `src/lib` directory.
**Example using `@lib` alias:**
```svelte
<script lang="ts">
import MyComponent from '$lib/components/MyComponent.svelte';
</script>
<MyComponent />
```
## $service-worker Module Details
The `$service-worker` module (service worker context only) provides variables for service worker logic:
- **`base`**: Base path of the deployment in service worker context.
- **`build`**: Array of build assets for caching.
- **`files`**: Array of static assets for caching.
- **`prerendered`**: Array of prerendered paths.
- **`version`**: Application version string.
## Conclusion
This cheat sheet summarizes the key features and concepts of SvelteKit with Svelte 5 runes. It should help junior developers quickly grasp the essentials for building performant and well-structured SvelteKit applications. For in-depth information, always refer back to the official SvelteKit documentation.
```
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment