Svelte 5 and SvelteKit Development Instructions
June 29, 2026 · View on GitHub
Instructions for building high-quality Svelte 5 and SvelteKit applications with modern runes-based reactivity, TypeScript, and performance optimization.
Note
Examples and APIs in this guide target Svelte 5.x and SvelteKit 2.x. Features noted as experimental (await expressions and remote functions) require opt-in config flags and may change before they stabilize.
Project Context
- Svelte 5.x with runes system (derived, props, $bindable)
- SvelteKit 2.x for full-stack applications with file-based routing
- TypeScript for type safety and better developer experience
- Component-scoped styling with CSS custom properties
- Progressive enhancement and performance-first approach
- Modern build tooling (Vite) with optimizations
Core Concepts
Architecture
- Use Svelte 5 runes system for all reactivity instead of legacy stores
- Organize components by feature or domain for scalability
- Separate presentation components from logic-heavy components
- Extract reusable logic into composable functions
- Implement proper component composition with slots and snippets
- Use SvelteKit's file-based routing with proper load functions
Component Design
- Follow single responsibility principle for components
- Use
<script lang="ts">with runes syntax as default - Keep components small and focused on one concern
- Implement proper prop validation with TypeScript annotations
- Use
{#snippet}blocks for reusable template logic within components - Use slots for component composition and content projection
- Pass
childrensnippet for flexible parent-child composition - Design components to be testable and reusable
- Prefer attachments (
{@attach}, Svelte 5.29+) over actions (use:) for DOM interaction and third-party library integration — attachments react to state and compose cleanly - Follow naming conventions: PascalCase for components, camelCase for functions and variables
- Document complex components and logic with JSDoc comments
Reactivity and State
Svelte 5 Runes System
- Use
$state()for reactive local state management - Implement
$derived()for computed values and expensive calculations - Use
$derived.by()for complex computations beyond simple expressions - Use
$effect()sparingly - prefer$derivedor function bindings for state sync - Implement
$effect.pre()for running code before DOM updates - Use
untrack()to prevent infinite loops when reading/writing same state in effects - Define component props with
$props()and destructuring with TypeScript annotations - Use
$bindable()for two-way data binding between components - Use function bindings (
bind:value={() => value, (v) => (value = v)}) when a binding needs to derive or validate the value - Migrate from legacy stores to runes for better performance
- Override derived values directly for optimistic UI patterns (Svelte 5.25+)
State Management
- Use
$state()for local component state - Implement type-safe context with
createContext()helper over rawsetContext/getContext - Use context API for sharing reactive state down component trees
- Avoid global
$statemodules for SSR - use context to prevent cross-request data leaks - Read SvelteKit app and navigation state from
$app/state(page,navigating,updated);$app/storesis the legacy equivalent for SvelteKit < 2.12 - Keep state normalized for complex data structures
- Prefer
$derived()over$effect()for computed values - Implement proper state persistence for client-side data
Effect Best Practices
- Avoid using
$effect()to synchronize state - use$derived()instead - Do use
$effect()for side effects: analytics, logging, DOM manipulation - Do return cleanup functions from effects for proper teardown
- Use
$effect.pre()when code must run before DOM updates (e.g., scroll position) - Use
$effect.root()for manually controlled effects outside component lifecycle - Use
untrack()to read state without creating dependencies in effects - Remember: async code in effects doesn't track dependencies after
await
SvelteKit Patterns
Routing and Layouts
- Use
+page.sveltefor page components with proper SEO - Implement
+layout.sveltefor shared layouts and navigation - Handle routing with SvelteKit's file-based system
Data Loading and Mutations
- Use
+page.server.tsfor server-side data loading and API calls - Implement form actions in
+page.server.tsfor data mutations - Use
+server.tsfor API endpoints and server-side logic - Use SvelteKit's load functions for server-side and universal data fetching
- Implement proper loading, error, and success states
- Handle streaming data with promises in server load functions
- Use
invalidate()andinvalidateAll()for cache management - Implement optimistic updates for better user experience
- Handle offline scenarios and network errors gracefully
Remote Functions (experimental)
- Use remote functions (SvelteKit 2.27+) for type-safe client-server calls that always run on the server; define them in
.remote.tsfiles as one ofquery,form,command, orprerender - Opt in by setting
kit.experimental.remoteFunctionsandcompilerOptions.experimental.asyncinsvelte.config.js - Read data with
queryand resolve it directly in markup withawait getPosts():
// src/routes/blog/data.remote.ts
import { query } from '$app/server';
import * as db from '$lib/server/database';
export const getPosts = query(async () => {
return await db.sql`SELECT title, slug FROM post ORDER BY published_at DESC`;
});
- Remote files may import
$lib/servermodules for secrets and DB access, but must not live insidesrc/lib/server
Forms and Validation
- Use SvelteKit's form actions for server-side form handling
- Implement progressive enhancement with
use:enhance - Use
bind:valuefor controlled form inputs - Validate data both client-side and server-side
- Handle file uploads and complex form scenarios
- Implement proper accessibility with labels and ARIA attributes
UI and Styling
Styling
- Use component-scoped styles with
<style>blocks - Implement CSS custom properties for theming and design systems
- Use
class:directive for conditional styling - Follow BEM or utility-first CSS conventions
- Implement responsive design with mobile-first approach
- Use
:global()sparingly for truly global styles
Transitions and Animations
- Use
transition:directive for enter/exit animations (fade, slide, scale, fly) - Use
in:andout:for separate enter/exit transitions - Implement
animate:directive withflipfor smooth list reordering - Create custom transitions for branded motion design
- Use
|localmodifier to trigger transitions only on direct changes - Combine transitions with keyed
{#each}blocks for list animations
TypeScript Integration
- Enable strict mode in
tsconfig.jsonfor maximum type safety - Annotate props with TypeScript:
let { name }: { name: string } = $props() - Type event handlers, refs, and SvelteKit's generated types
- Use generic types for reusable components
- Leverage
$types.tsfiles generated by SvelteKit - Implement proper type checking with
svelte-check - Use type inference where possible to reduce boilerplate
Code Quality
Performance Optimization
- Use keyed
{#each}blocks for efficient list rendering - Implement lazy loading with dynamic
import(); in Svelte 5 components are dynamic by default — assign the imported component to a capitalized variable and render<Component />(<svelte:component>is no longer needed in runes mode) - Use
$derived()for expensive computations to avoid unnecessary recalculations - Use
$derived.by()for complex derived values that require multiple statements - Avoid
$effect()for derived state - it's less efficient than$derived() - Leverage SvelteKit's automatic code splitting and preloading
- Optimize bundle size with tree shaking and proper imports
- Use
$effect.tracking()in abstractions to conditionally create reactive listeners
Error Handling
- Implement
+error.sveltepages for route-level error boundaries - Use
<svelte:boundary>(Svelte 5.3+) to contain rendering and effect errors at the component level, providing afailedsnippet (withreset) or anonerrorhandler for fallback UI - Use try/catch blocks in load functions and form actions
- Provide meaningful error messages and fallback UI
- Log errors appropriately for debugging
- Handle validation errors in forms with proper user feedback
- Use SvelteKit's
error()andredirect()helpers for proper responses - With the experimental
awaitsyntax (Svelte 5.36+, opt-in viaexperimental.async), show first-render UI with a<svelte:boundary>pendingsnippet and later loading states with$effect.pending()
Security
- Sanitize user inputs to prevent XSS attacks
- Use
@htmldirective carefully and validate HTML content - Validate and sanitize data in load functions and form actions
Accessibility
- Use semantic HTML elements and proper heading hierarchy
- Implement keyboard navigation for all interactive elements
- Provide proper ARIA labels and descriptions
- Ensure color contrast meets WCAG guidelines
- Implement focus management for dynamic content