Project Setup
Setting up a SvelteKit project takes about two minutes. The tooling is batteries-included: TypeScript, Vite, path aliases, SSR, and hot module replacement work out of the box. This topic covers the project scaffold, what each file and directory does, and how to configure the pieces that matter.
Creating a Project
The official way to create a SvelteKit project is with sv:
npx sv create my-app
cd my-app
npm install
npm run dev
The sv create wizard prompts you to choose:
- Template: Minimal (bare-bones) or demo app (example routes and components).
- TypeScript: Yes or no. Choose yes. The type safety pays for itself immediately.
- Add-ons: ESLint, Prettier, Playwright, Vitest, and others. You can add these later, but it is easier to include them upfront.
After installation, npm run dev starts a development server at http://localhost:5173 with hot module replacement enabled.
Project Structure
A freshly scaffolded SvelteKit project looks like this:
my-app/
src/
lib/
index.ts
routes/
+page.svelte
+layout.svelte
app.html
app.d.ts
static/
favicon.png
svelte.config.js
vite.config.ts
tsconfig.json
package.json
src/routes/
This is where your pages live. SvelteKit uses file-based routing. Every +page.svelte file inside src/routes/ becomes a route:
src/routes/+page.svelte -> /
src/routes/about/+page.svelte -> /about
src/routes/blog/[slug]/+page.svelte -> /blog/:slug
Route directories can also contain:
+page.tsor+page.server.tsfor data loading.+layout.sveltefor shared layouts.+error.sveltefor error pages.+server.tsfor API endpoints.
src/lib/
This is the shared library directory. Code here is importable with the $lib alias:
// src/lib/utils.ts
export function formatDate(date: Date): string {
return date.toLocaleDateString('en-US', {
year: 'numeric', month: 'long', day: 'numeric'
});
}
<!-- src/routes/+page.svelte -->
<script>
import { formatDate } from '$lib/utils';
</script>
Organize src/lib/ however makes sense for your project. A common layout:
src/lib/
components/ # Shared components
server/ # Server-only utilities
stores/ # Svelte stores
utils/ # Helper functions
types.ts # Shared TypeScript types
src/app.html
The HTML shell for your application. SvelteKit injects the rendered page into this template:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-prerender="true">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
%sveltekit.head% is replaced with <title>, meta tags, and preloaded assets. %sveltekit.body% is replaced with the rendered page content.
static/
Files in static/ are served as-is at the root of your site. static/robots.txt becomes https://yoursite.com/robots.txt. Put images, fonts, and other assets that do not need processing here.
For assets that should be processed by Vite (optimized, hashed, tree-shaken), import them in your Svelte or TypeScript files instead:
<script>
import logo from '$lib/assets/logo.svg';
</script>
<img src={logo} alt="Logo">
Configuration Files
svelte.config.js
The central configuration file for SvelteKit. It controls the adapter (deployment target), preprocessors, and various SvelteKit options:
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter(),
alias: {
$components: 'src/lib/components',
$utils: 'src/lib/utils'
}
}
};
export default config;
The adapter determines how your app is built for deployment:
@sveltejs/adapter-auto: Detects deployment platform automatically.@sveltejs/adapter-node: Builds a Node.js server.@sveltejs/adapter-static: Generates a fully static site.@sveltejs/adapter-vercel,@sveltejs/adapter-cloudflare: Platform-specific adapters.
vite.config.ts
SvelteKit runs on Vite. Most of the time you do not need to touch this file, but it is where you add Vite plugins or configure the dev server:
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
server: {
port: 3000
}
});
tsconfig.json
The TypeScript configuration extends SvelteKit's generated config. The generated .svelte-kit/tsconfig.json sets up path aliases ($lib, $app, etc.) and Svelte-specific type handling:
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"strict": true
}
}
Do not remove the extends line. The generated config handles the $lib alias, Svelte file type resolution, and other SvelteKit-specific settings.
TypeScript Setup
SvelteKit has first-class TypeScript support. In .svelte files, add lang="ts" to the script tag:
<script lang="ts">
interface User {
id: number;
name: string;
email: string;
}
let { user }: { user: User } = $props();
</script>
<p>{user.name} ({user.email})</p>
SvelteKit auto-generates types for your routes. After running the dev server or npm run build, you get typed data props in your pages:
<!-- src/routes/+page.svelte -->
<script lang="ts">
let { data } = $props();
// `data` is typed based on what +page.ts returns
</script>
Path Aliases
$lib is the built-in alias for src/lib/. You can add custom aliases in svelte.config.js:
kit: {
alias: {
$components: 'src/lib/components',
$server: 'src/lib/server',
$types: 'src/lib/types'
}
}
These aliases work in both .svelte and .ts files, and TypeScript understands them automatically.
The Dev Server & Hot Module Replacement
npm run dev starts Vite's development server. Key features:
- Hot Module Replacement (HMR): When you save a file, the browser updates without a full page reload. Component state is preserved when possible.
- Fast startup: Vite serves modules on demand rather than bundling everything upfront.
- Error overlay: Compile errors appear directly in the browser with source-mapped stack traces.
For the best development experience:
npm run dev -- --open # Opens browser automatically
npm run dev -- --host # Exposes to network (useful for mobile testing)
Build & Preview
npm run build # Production build
npm run preview # Preview the production build locally
The build output depends on your adapter. adapter-node produces a Node.js server in build/. adapter-static produces static HTML/CSS/JS in build/. The preview command lets you test the production build locally before deploying.
Common Pitfalls
- Editing the generated .svelte-kit directory: This directory is auto-generated and overwritten. Never edit files inside it. If something looks wrong, delete it and re-run
npm run dev. - **Forgetting to use lib/utils` instead.
- Putting server-only code in shared files: Code in
$lib/can run on both server and client. If you import a Node.js module (likefs) in a shared file, the client build will fail. Use$lib/server/for server-only code, or put it in+page.server.tsfiles. - Ignoring TypeScript: Svelte 5's runes and SvelteKit's typed data loading work significantly better with TypeScript. The investment in type annotations pays off in autocomplete, error catching, and documentation.
- Not choosing an adapter:
adapter-autoworks for platforms it recognizes, but you should explicitly choose an adapter for your deployment target. Auto-detection can produce unexpected results.
Key Takeaways
npx sv createscaffolds a complete SvelteKit project with TypeScript, Vite, and sensible defaults.src/routes/is file-based routing.src/lib/is shared code accessible via the$libalias.svelte.config.jscontrols adapters, aliases, and preprocessing.vite.config.tshandles Vite-specific configuration.- TypeScript is strongly recommended and well-supported. SvelteKit auto-generates route types.
- The dev server provides hot module replacement with instant feedback. Build output depends on your chosen adapter.
- Keep server-only code in
$lib/server/or+page.server.tsto avoid client-side build errors.