A scalable, production-grade SvelteKit boilerplate configured as a client-side SPA (no SSR). Designed to work with a separate Express.js backend API.
| Category | Tool |
|---|---|
| Framework | SvelteKit 2 + Svelte 5 (Runes) |
| Language | TypeScript (strict) |
| Styling | TailwindCSS v4 |
| Linting | ESLint + Prettier |
| Unit Testing | Vitest |
| E2E Testing | Playwright |
| Validation | Zod |
| Build Output | Static files (adapter-static) |
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env
# Start development server
npm run dev
The dev server runs on http://localhost:5173. API requests to /api/* are proxied to http://localhost:3000 (Express.js).
src/
├── lib/
│ ├── domains/ # Business domain modules
│ │ ├── auth/ # Auth domain (types, service, store)
│ │ └── [domain]/ # Add more domains here
│ ├── shared/
│ │ ├── components/ # Reusable UI components
│ │ ├── utils/ # Utilities (API client, validation, formatters)
│ │ ├── constants/ # App-wide constants
│ │ └── types/ # Shared TypeScript types
│ └── guards/ # Route guards (auth, roles)
├── routes/
│ ├── (auth)/ # Public auth pages (login, register)
│ ├── (app)/ # Protected pages (dashboard, etc.)
│ └── +layout.svelte # Root layout
└── params/ # Custom route param matchers
Each domain (e.g., auth, products, users) is self-contained:
src/lib/domains/my-domain/
├── components/ # Domain-specific UI
├── services/ # API calls & business logic
├── stores/ # Reactive state (Runes)
├── types.ts # Types & Zod schemas
└── index.ts # Public API (barrel export)
| Alias | Path |
|---|---|
$lib |
src/lib |
$domains |
src/lib/domains |
$shared |
src/lib/shared |
$guards |
src/lib/guards |
The API client ($shared/utils/api.ts) provides typed HTTP methods:
import { get, post, getData } from '$shared/utils/api';
import type { ApiResponse, PaginatedResponse } from '$shared/types';
// GET with full response
const response = await get<ApiResponse<User>>('/users/1');
// GET and unwrap data
const user = await getData<User>('/users/1');
// POST with body
const created = await post<ApiResponse<User>>('/users', { name: 'John' });
Features:
authService.login() calls Express APIauthStore tracks reactive user state via Svelte 5 Runes$guards/auth.guard.ts) protect pagessrc/lib/domains/products/types.ts with Zod schemasservices/product.service.ts with API callsstores/product.store.svelte.ts with Runes stateindex.ts barrel exportsrc/routes/(app)/products/+page.sveltenpm run dev # Start dev server
npm run build # Build for production (static output)
npm run preview # Preview production build
npm run check # TypeScript type check
npm run lint # ESLint + Prettier check
npm run format # Auto-format with Prettier
npm run test:unit # Run unit tests (Vitest)
npm run test:e2e # Run E2E tests (Playwright)
npm run test # Run all tests
| Variable | Description | Default |
|---|---|---|
VITE_APP_NAME |
Application name | My App |
VITE_APP_URL |
Application URL | http://localhost:5173 |
VITE_API_BASE_URL |
Express.js API URL | http://localhost:3000/api |
VITE_TOKEN_KEY |
LocalStorage key for auth token | auth_token |
VITE_REFRESH_TOKEN_KEY |
LocalStorage key for refresh token | refresh_token |
This boilerplate outputs static files via adapter-static. Deploy to any static host:
npm run build
# Output in /build directory
Deploy /build to: Nginx, Apache, Vercel, Netlify, Cloudflare Pages, S3 + CloudFront, etc.
Important: Configure your web server to serve
index.htmlfor all routes (SPA fallback).
server {
listen 80;
root /var/www/app/build;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:3000;
}
}
MIT