Framework & Full-Stack SvelteKit TypeScript

SvelteKit mit Claude Code: TypeScript Full-Stack Framework 2026

Routing, Svelte 5 Runes, Form Actions, Load Functions, Hooks und Deployment-Adapters — alles, was du für professionelle SvelteKit-Entwicklung mit KI brauchst.

SvelteKit hat sich 2026 als das schnellste und produktivste Full-Stack-Framework im JavaScript-Ökosystem etabliert. In Kombination mit Claude Code entsteht ein Workflow, der TypeScript-Entwicklung dramatisch beschleunigt: von der Projektstruktur über typisierte Load Functions bis hin zu progressiv enhancten Form Actions. Dieser Artikel zeigt, wie du SvelteKit-Projekte mit Claude Code effizient entwickelst — mit echten TypeScript-Beispielen für jede Schicht der Anwendung.

Was du lernst: SvelteKit-Routing, Svelte 5 Runes, Load Functions, Form Actions, Hooks & Middleware, Adapter-Deployment — alles typsicher mit TypeScript und KI-Unterstützung durch Claude Code.

1. SvelteKit Setup & Routing

SvelteKit nutzt ein dateibasiertes Routing-System, das sich direkt aus der Verzeichnisstruktur unter src/routes/ ableitet. Jede Route besteht aus klar definierten Dateitypen: +page.svelte für die UI-Komponente, +layout.svelte für geteilte Layouts, +page.ts oder +page.server.ts für Load Functions sowie +server.ts für API-Endpoints.

ROUTING

Projektstruktur mit Claude Code erstellen

Claude Code versteht SvelteKit-Konventionen und kann vollständige Routing-Strukturen generieren. Prompt-Beispiel:

# Prompt an Claude Code: "Erstelle eine SvelteKit TypeScript App mit: - Öffentliche Routen: /, /blog, /blog/[slug] - Auth-geschützte Routen: /dashboard, /dashboard/settings - Route Group (marketing) für shared Layout - API-Endpoint /api/posts"

Claude generiert die korrekte Verzeichnisstruktur:

src/routes/ ├── (marketing)/ │ ├── +layout.svelte # Shared marketing layout │ ├── +page.svelte # Startseite │ └── blog/ │ ├── +page.svelte # Blog-Übersicht │ ├── +page.ts # Load Function (client + server) │ └── [slug]/ │ ├── +page.svelte # Blog-Detailseite │ └── +page.server.ts # Server Load Function ├── dashboard/ │ ├── +layout.server.ts # Auth-Check für alle /dashboard Routen │ ├── +layout.svelte │ ├── +page.svelte │ └── settings/ │ └── +page.svelte └── api/ └── posts/ └── +server.ts # REST API Endpoint

+page.svelte — Grundstruktur mit TypeScript

<!-- src/routes/(marketing)/blog/+page.svelte --> <script lang="ts"> import type { PageData } from './$types'; let { data }: { data: PageData } = $props(); </script> <svelte:head> <title>{data.title} | Mein Blog</title> <meta name="description" content={data.description} /> </svelte:head> <main> <h1>Blog</h1> {#each data.posts as post (post.id)} <article> <h2><a href="/blog/{post.slug}">{post.title}</a></h2> <p>{post.excerpt}</p> </article> {/each} </main>

+layout.svelte mit Slot und Navigation

<!-- src/routes/(marketing)/+layout.svelte --> <script lang="ts"> import type { LayoutData } from './$types'; import Nav from '$lib/components/Nav.svelte'; import Footer from '$lib/components/Footer.svelte'; let { data, children }: { data: LayoutData; children: Snippet } = $props(); </script> <Nav user={data.user} /> <main class="container"> {@render children()} </main> <Footer />

Dynamische Routen mit [slug]

<!-- src/routes/(marketing)/blog/[slug]/+page.svelte --> <script lang="ts"> import type { PageData } from './$types'; let { data }: { data: PageData } = $props(); </script> <article class="prose"> <h1>{data.post.title}</h1> <time>{data.post.publishedAt}</time> <div class="content">{@html data.post.content}</div> </article>
Claude Code Tipp: Gib Claude den vollständigen Pfad und den gewünschten Typ (+page.svelte, +page.server.ts etc.) im Prompt an. Claude kennt alle SvelteKit-Konventionen und generiert korrekte TypeScript-Typen aus ./$types automatisch.

Route Groups und API-Endpoints

Route Groups mit (groupname)-Syntax erlauben gemeinsame Layouts ohne URL-Einfluss. API-Endpoints via +server.ts unterstützen alle HTTP-Methoden typsicher:

// src/routes/api/posts/+server.ts import type { RequestHandler } from './$types'; import { json } from '@sveltejs/kit'; import { db } from '$lib/server/db'; export const GET: RequestHandler = async ({ url }) => { const limit = Number(url.searchParams.get('limit') ?? '10'); const posts = await db.posts.findMany({ take: limit }); return json(posts); }; export const POST: RequestHandler = async ({ request }) => { const body = await request.json(); const post = await db.posts.create({ data: body }); return json(post, { status: 201 }); };

2. Svelte 5 Runes & Reaktivität

Svelte 5 führt Runes als explizites reaktives Primitiv-System ein. Anstatt impliziter Reaktivität durch deklarierte Variablen verwendet Svelte 5 explizite Runes-Aufrufe: $state, $derived, $effect und $props. Das macht den Code lesbarer, vorhersehbarer — und für Claude Code erheblich einfacher zu generieren und zu debuggen.

SVELTE 5

Runes vs. klassische Stores im Vergleich

Feature Svelte 4 (alt) Svelte 5 Runes
Reaktiver State let count = 0 (implizit) let count = $state(0)
Abgeleiteter Wert $: doubled = count * 2 let doubled = $derived(count * 2)
Side Effects $: { effect() } $effect(() => { effect() })
Props export let name let { name } = $props()
TypeScript Umständlich Vollständig typsicher

$state — Reaktiver State mit TypeScript Generics

<!-- src/lib/components/Counter.svelte --> <script lang="ts"> // Einfacher State let count = $state(0); // Typisierter State mit Interface interface User { id: string; name: string; email: string; } let user = $state<User | null>(null); // Array State — reaktiv auf push/splice etc. let items = $state<string[]>([]); function addItem(item: string) { items.push(item); // Direkte Mutation — Svelte 5 trackt das! } </script> <button onclick={() => count++}>Clicks: {count}</button>

$derived — Berechnete Werte

<script lang="ts"> let firstName = $state(''); let lastName = $state(''); // Einfache Ableitung let fullName = $derived(`${firstName} ${lastName}`.trim()); // Komplexe Ableitung mit $derived.by() let cartTotal = $derived.by(() => { return items.reduce((sum, item) => sum + item.price * item.quantity, 0); }); // TypeScript Generics in derived let filteredPosts = $derived<Post[]>( posts.filter(p => p.published && p.category === selectedCategory) ); </script>

$effect — Reaktive Seiteneffekte

<script lang="ts"> let searchQuery = $state(''); let results = $state<SearchResult[]>([]); let loading = $state(false); // Läuft wenn searchQuery sich ändert $effect(async () => { if (!searchQuery) { results = []; return; } loading = true; const res = await fetch(`/api/search?q=${searchQuery}`); results = await res.json(); loading = false; }); // Cleanup-Funktion für Event Listener $effect(() => { const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') searchQuery = ''; }; document.addEventListener('keydown', handler); return () => document.removeEventListener('keydown', handler); }); </script>

$props — Typisierte Komponenten-Props

<!-- src/lib/components/Button.svelte --> <script lang="ts"> import type { Snippet } from 'svelte'; interface Props { variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; onclick?: () => void; children: Snippet; } let { variant = 'primary', size = 'md', disabled = false, onclick, children }: Props = $props(); </script> <button class="btn btn-{variant} btn-{size}" {disabled} {onclick} > {@render children()} </button>
Claude Code Tipp: Beschreibe die gewünschte Komponenten-API mit Props-Interface und Slot-Struktur. Claude generiert vollständig typsichere Svelte-5-Komponenten mit korrekten Runes-Aufrufen und Snippet-Typen.

3. Load Functions & Data Fetching

Load Functions sind das Herzstück des SvelteKit-Datenflusses. Sie laufen vor dem Rendering der Seite, entweder nur auf dem Server (+page.server.ts), auf Client und Server (+page.ts) oder im Layout (+layout.server.ts). Das TypeScript-Typsystem von SvelteKit stellt sicher, dass data in +page.svelte immer den korrekten Typ aus der Load Function hat.

LOAD

+page.server.ts — Server-only Load Function

// src/routes/(marketing)/blog/[slug]/+page.server.ts import type { PageServerLoad } from './$types'; import { error } from '@sveltejs/kit'; import { db } from '$lib/server/db'; export const load: PageServerLoad = async ({ params, locals }) => { // params.slug ist typsicher durch SvelteKit const post = await db.posts.findUnique({ where: { slug: params.slug, published: true }, include: { author: true, tags: true } }); if (!post) { throw error(404, { message: 'Artikel nicht gefunden' }); } // Nur serialisierbare Daten zurückgeben return { post, relatedPosts: await db.posts.findMany({ where: { tags: { some: { id: { in: post.tags.map(t => t.id) } } } }, take: 3 }), isLoggedIn: !!locals.user }; };

+page.ts — Universelle Load Function (Client + Server)

// src/routes/(marketing)/blog/+page.ts import type { PageLoad } from './$types'; export const load: PageLoad = async ({ fetch, url }) => { // fetch ist ein SvelteKit-patch von fetch — SSR-sicher const page = Number(url.searchParams.get('page') ?? '1'); const [posts, categories] = await Promise.all([ fetch(`/api/posts?page=${page}&limit=10`).then(r => r.json()), fetch('/api/categories').then(r => r.json()) ]); return { posts, categories, currentPage: page, title: 'Blog', description: 'Alle Artikel zu KI-Entwicklung' }; };

LayoutServerLoad — Globale Auth-Daten

// src/routes/+layout.server.ts import type { LayoutServerLoad } from './$types'; export const load: LayoutServerLoad = async ({ locals }) => { // locals.user wird in hooks.server.ts gesetzt return { user: locals.user ?? null }; };

parent() und depends() für Cache-Invalidierung

// src/routes/dashboard/+page.server.ts import type { PageServerLoad } from './$types'; import { redirect } from '@sveltejs/kit'; export const load: PageServerLoad = async ({ parent, depends }) => { // Daten aus dem übergeordneten Layout laden const { user } = await parent(); if (!user) { throw redirect(303, '/login'); } // Cache-Key für invalidate() im Client depends('app:dashboard'); return { stats: await fetchDashboardStats(user.id), recentActivity: await fetchActivity(user.id, { limit: 10 }) }; };
Claude Code Tipp: Zeige Claude eine bestehende Load Function und frage nach Erweiterungen wie Caching, Fehlerbehandlung oder Parallel-Fetching. Claude ergänzt den Code korrekt und behält die TypeScript-Typen bei.

4. Form Actions & Progressive Enhancement

Form Actions sind SvelteKits Antwort auf die Frage: Wie verarbeitet man Formulardaten serverseitig — ohne API-Layer, ohne CORS, ohne manuelle Fehlerbehandlung? Mit use:enhance werden Forms progressiv verbessert: Sie funktionieren ohne JavaScript (Plain HTML Form Submit) und werden mit JS zu einer SPA-Experience. Claude Code kann komplexe Form-Action-Patterns mit superforms-Integration generieren.

ACTIONS

Default und Named Actions

// src/routes/contact/+page.server.ts import type { Actions, PageServerLoad } from './$types'; import { fail, redirect } from '@sveltejs/kit'; import { z } from 'zod'; const contactSchema = z.object({ name: z.string().min(2, 'Name zu kurz'), email: z.string().email('Ungültige E-Mail'), message: z.string().min(10, 'Nachricht zu kurz') }); export const actions: Actions = { // Default Action: ?/default oder einfach POST default: async ({ request }) => { const formData = await request.formData(); const raw = Object.fromEntries(formData); const result = contactSchema.safeParse(raw); if (!result.success) { return fail(400, { errors: result.error.flatten().fieldErrors, values: raw }); } await sendEmail(result.data); throw redirect(303, '/contact/success'); }, // Named Action: ?/subscribe subscribe: async ({ request }) => { const formData = await request.formData(); const email = formData.get('email') as string; if (!email) return fail(400, { emailError: 'E-Mail erforderlich' }); await addToNewsletter(email); return { success: true, message: 'Erfolgreich angemeldet!' }; } };

use:enhance — Progressive Enhancement im Template

<!-- src/routes/contact/+page.svelte --> <script lang="ts"> import { enhance } from '$app/forms'; import type { ActionData } from './$types'; let { form }: { form: ActionData } = $props(); let submitting = $state(false); </script> <form method="POST" use:enhance={({ formElement, formData, action, cancel }) => { submitting = true; // Optionaler Custom-Handler vor Submit return async ({ result, update }) => { submitting = false; if (result.type === 'success') { formElement.reset(); } await update(); }; }} > <label> Name <input name="name" value={form?.values?.name ?? ''} /> {#if form?.errors?.name} <span class="error">{form.errors.name[0]}</span> {/if} </label> <button type="submit" disabled={submitting}> {submitting ? 'Senden...' : 'Absenden'} </button> </form>

Superforms Integration für komplexe Formulare

// src/routes/dashboard/profile/+page.server.ts import { superValidate, fail } from 'sveltekit-superforms'; import { zod } from 'sveltekit-superforms/adapters'; import { z } from 'zod'; const profileSchema = z.object({ displayName: z.string().min(2).max(50), bio: z.string().max(500).optional(), website: z.string().url().optional() }); export const load: PageServerLoad = async ({ locals }) => { const form = await superValidate(locals.user, zod(profileSchema)); return { form }; }; export const actions: Actions = { default: async ({ request, locals }) => { const form = await superValidate(request, zod(profileSchema)); if (!form.valid) return fail(400, { form }); await db.users.update({ where: { id: locals.user.id }, data: form.data }); return { form }; } };

5. Hooks & Middleware

SvelteKit Hooks erlauben Middleware-Logik auf Server-Ebene: Authentifizierung, Logging, CORS-Header, Locale-Detection und mehr. Die Hooks laufen vor jeder Request-Verarbeitung und haben Zugriff auf das event-Objekt mit Request, Cookies, Locals und URL.

HOOKS

hooks.server.ts — handle, handleError, handleFetch

// src/hooks.server.ts import type { Handle, HandleError, HandleFetch } from '@sveltejs/kit'; import { sequence } from '@sveltejs/kit/hooks'; import { db } from '$lib/server/db'; import { verifyToken } from '$lib/server/auth'; // Authentifizierungs-Hook const authHook: Handle = async ({ event, resolve }) => { const token = event.cookies.get('session_token'); if (token) { try { const payload = verifyToken(token); event.locals.user = await db.users.findUnique({ where: { id: payload.userId } }); } catch { event.cookies.delete('session_token', { path: '/' }); } } return resolve(event); }; // Security-Headers-Hook const securityHook: Handle = async ({ event, resolve }) => { const response = await resolve(event); response.headers.set('X-Frame-Options', 'DENY'); response.headers.set('X-Content-Type-Options', 'nosniff'); response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin'); return response; }; // Mehrere Hooks mit sequence() verketten export const handle: Handle = sequence(authHook, securityHook);

handleError — Globale Fehlerbehandlung

// src/hooks.server.ts (Fortsetzung) export const handleError: HandleError = async ({ error, event, status, message }) => { const errorId = crypto.randomUUID(); // In Logging-Service schreiben console.error({ errorId, status, message, path: event.url.pathname, error: error instanceof Error ? error.stack : error }); // Sentry, Datadog etc. hier integrieren if (status >= 500) { await notifySlack({ errorId, message, path: event.url.pathname }); } // Rückgabe erscheint in $page.error return { message: status === 404 ? 'Seite nicht gefunden' : 'Ein Fehler ist aufgetreten', errorId }; };

handleFetch — Outgoing Requests modifizieren

// Nützlich für: Auth-Header zu internen APIs, Request-Logging, Caching export const handleFetch: HandleFetch = async ({ request, fetch, event }) => { // Interne API-Calls während SSR mit Auth-Token versehen if (request.url.startsWith('http://localhost')) { const token = event.cookies.get('session_token'); if (token) { request = new Request(request, { headers: { ...Object.fromEntries(request.headers), Authorization: `Bearer ${token}` } }); } } return fetch(request); };

TypeScript App.Locals — Typsichere Locals

// src/app.d.ts — Globale TypeScript-Declarations für SvelteKit import type { User } from '$lib/types'; declare global { namespace App { interface Locals { user: User | null; session: { id: string; expiresAt: Date } | null; } interface Error { message: string; errorId?: string; } interface PageData { user?: User | null; } interface PageState { modal?: 'login' | 'register' | null; } } } export {};
Claude Code Tipp: Beschreibe dein Authentifizierungsschema (JWT, Session, OAuth) und frage Claude nach einer vollständigen Hook-Implementierung. Claude generiert authHook, handleError und app.d.ts als konsistentes System.

6. Adapters & Deployment

SvelteKit ist plattformagnostisch durch sein Adapter-System. Jeder Adapter optimiert den Output für eine spezifische Zielplattform: Node.js-Server, Vercel Edge Functions, Cloudflare Workers oder statische Dateien. Die Wahl des Adapters hat keine Auswirkung auf den Anwendungscode — nur svelte.config.js ändert sich.

DEPLOY

Adapter-Vergleich 2026

Adapter Plattform Use Case Cold Start
adapter-node Node.js VPS Self-hosted, Docker, Railway Kein (always-on)
adapter-vercel Vercel Edge/Lambda Einfaches Deployment, Auto-Scaling ~100ms (Edge)
adapter-cloudflare Cloudflare Workers Global Edge, KV/D1/R2 ~0ms
adapter-static Beliebiges CDN Reine SPA/Static Sites N/A
adapter-bun Bun Runtime Schnelle Node-Alternative Kein (always-on)

adapter-node — Self-hosted mit Docker

// svelte.config.js import adapter from '@sveltejs/adapter-node'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; export default { preprocess: vitePreprocess(), kit: { adapter: adapter({ out: 'build', precompress: true, // Gzip + Brotli envPrefix: 'PUBLIC_' // PUBLIC_* Variablen im Client }) } };
# Dockerfile für SvelteKit adapter-node FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-alpine AS runner WORKDIR /app COPY --from=builder /app/build ./build COPY --from=builder /app/package.json . RUN npm ci --production EXPOSE 3000 CMD ["node", "build"]

adapter-vercel — Edge Functions

// svelte.config.js import adapter from '@sveltejs/adapter-vercel'; export default { kit: { adapter: adapter({ runtime: 'edge', // oder 'nodejs20.x' regions: ['fra1', 'iad1'], // Frankfurt + Virginia isr: { expiration: 3600 // ISR: 1 Stunde Cache } }) } };

adapter-cloudflare — Workers mit KV und D1

// svelte.config.js import adapter from '@sveltejs/adapter-cloudflare'; export default { kit: { adapter: adapter({ routes: { include: ['/*'], exclude: ['/static/*'] } }) } }; // In +page.server.ts: Cloudflare Bindings nutzen export const load: PageServerLoad = async ({ platform }) => { const { DB, KV, R2 } = platform!.env; // D1 Database Query const posts = await DB.prepare('SELECT * FROM posts LIMIT 10').all(); // KV Store lesen const cached = await KV.get('homepage_data', 'json'); return { posts: posts.results, cached }; };

Environment Variables — PUBLIC_ vs. Private

// .env DATABASE_URL="postgresql://..." # Nur Server JWT_SECRET="..." # Nur Server PUBLIC_APP_URL="https://meine-app.de" # Client + Server PUBLIC_STRIPE_KEY="pk_live_..." # Client + Server // Server-only import (sicher) import { DATABASE_URL, JWT_SECRET } from '$env/static/private'; // Client + Server (PUBLIC_ Prefix pflicht) import { PUBLIC_APP_URL } from '$env/static/public'; // Dynamische Envs (zur Laufzeit) import { env } from '$env/dynamic/private';
Claude Code Tipp: Nenne Claude deine Zielplattform (Vercel, Cloudflare, Self-hosted Node) und bestehende Services (Datenbank, Auth-Provider). Claude generiert die passende svelte.config.js, Dockerfile/Deployment-Konfiguration und Environment-Variable-Struktur als vollständiges Setup.

Deployment-Workflow mit Claude Code

# Typischer Prompt für komplettes Deployment-Setup: "Ich deploye meine SvelteKit App auf einen Ubuntu VPS mit: - PostgreSQL (lokal via Prisma) - Nginx als Reverse Proxy - PM2 für Process Management - GitHub Actions für CI/CD Erstelle alle Konfigurationsdateien." # Claude generiert: # - svelte.config.js mit adapter-node # - .github/workflows/deploy.yml # - nginx.conf mit SSL-Konfiguration # - ecosystem.config.js für PM2 # - .env.production Template

Zusammenfassung: SvelteKit + Claude Code = Produktivitätsmultiplikator

SvelteKit bietet mit seinem konventionsbasierten Routing, den typsicheren Load Functions und dem progressiven Enhancement-Ansatz von Form Actions eine ideale Grundlage für KI-gestützte Entwicklung. Claude Code versteht die SvelteKit-Konventionen tief genug, um:

Svelte 5 Runes machen den Code dabei lesbarer und expliziter — was Claude Code die Generierung und das Debugging erheblich vereinfacht. Das Ergebnis: Full-Stack TypeScript-Apps in einem Bruchteil der üblichen Entwicklungszeit.

SvelteKit-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges SvelteKit-Modul mit Svelte 5 Runes, Form Actions, Load Functions, Hooks und Deployment-Adaptern.

14 Tage kostenlos testen →