SvelteKit Architecture

Overview

The Refresh App Web is built with SvelteKit 2 and Svelte 5, leveraging the latest features for server-side rendering (SSR), reactive UI, and file-based routing. The application is deployed on Cloudflare Workers using the @sveltejs/adapter-cloudflare adapter, enabling edge-based rendering globally.

SvelteKit 2 Overview

SvelteKit is a meta-framework for Svelte that provides:

  • Server-Side Rendering (SSR): Pages are pre-rendered at the edge

  • File-Based Routing: Routes are defined by the directory structure

  • Load Functions: Type-safe data fetching on server and client

  • Form Actions: Server-side form handling with progressive enhancement

  • Layouts: Nested layouts for code reuse

  • Hooks: Middleware-like functionality for request handling

Svelte 5 Runes

Svelte 5 introduces runes for explicit reactivity:

// State management
let count = $state(0);

// Derived state
let doubled = $derived(count * 2);

// Props (in components)
let { user, tenants } = $props();

// Effects
$effect(() => {
	console.log(`Count is now ${count}`);
});

Key Benefits:

  • More explicit reactivity model

  • Better TypeScript support

  • Improved performance

  • Easier testing

Project Structure

Routing

File-Based Routing

Routes are defined by the file system:

File
Purpose
Example

+page.svelte

Page component

/app/settingsroutes/app/settings/+page.svelte

+page.server.ts

Server-side load function

Data fetching, form actions

+layout.svelte

Layout component

Wraps child pages

+layout.server.ts

Layout server load

Shared data for nested routes

+server.ts

API endpoint

JSON responses, file uploads

+error.svelte

Error boundary

Custom error pages

Layout Groups

Layout groups use parentheses to organize routes without affecting URLs:

Benefits:

  • Enforce authentication at layout level

  • Share layouts without URL nesting

  • Organize related routes

Route Parameters

Dynamic routes use [param] syntax:

Access via params:

Server-Side Rendering (SSR)

How SSR Works

  1. Request arrives at Cloudflare edge

  2. Server hooks execute (security, auth, tenant context)

  3. Load function runs on server

  4. Page is rendered to HTML

  5. HTML sent to client with embedded data

  6. Hydration occurs - Svelte takes over on client

Load Functions

Server-side load (+page.server.ts):

Universal load (+page.ts) - runs on both server and client:

Form Actions

Server-side form handling with progressive enhancement:

In component:

Layouts

Nested Layouts

Layouts wrap their child routes and can be nested:

Result: Settings page has 4 nested layouts.

Layout Inheritance

Child routes inherit parent layouts:

Layout Data Loading

Layouts can load shared data:

Accessible in all child routes via data prop.

Hooks

Server Hooks (hooks.server.ts)

Hooks run on every request, acting as middleware:

Hook Sequence

Hooks execute in order:

  1. Security Handle - HTTPS redirect, security headers

  2. Auth Handle - Authentication, session management

  3. PostHog Handle - Analytics proxy for /relay-uBFJ

Event Locals

Hooks can set event.locals for downstream use:

Cloudflare Adapter

Configuration

svelte.config.js:

Build Output

Cloudflare Bindings

Access Cloudflare services via platform:

wrangler.toml:

Type Safety

Generated Types

SvelteKit generates types for routes:

In component:

App Type Declaration

src/app.d.ts:

Performance Optimizations

Code Splitting

vite.config.ts:

Lazy Loading

Preloading

Error Handling

Error Pages

routes/+error.svelte:

Error Boundaries

Global Error Handler

hooks.server.ts:

Testing

Component Testing

Vitest Configuration

vite.config.ts:

Best Practices

1. Use Server-Side Load Functions

Fetch data on the server for better performance and SEO:

2. Leverage Layouts for Shared Logic

3. Use Form Actions for Mutations

4. Type Everything

Use generated types from ./$types:

5. Optimize Bundle Size

  • Use code splitting for large dependencies

  • Lazy load components that aren't immediately needed

  • Preload critical routes


Last updated: October 2025

Last updated