4 min read
On this page

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.ts or +page.server.ts for data loading.
  • +layout.svelte for shared layouts.
  • +error.svelte for error pages.
  • +server.ts for 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 libforimports:Relativeimportslike../../../lib/utilsarefragileandhardtoread.Alwaysuselib for imports**: Relative imports like `../../../lib/utils` are fragile and hard to read. Always 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 (like fs) in a shared file, the client build will fail. Use $lib/server/ for server-only code, or put it in +page.server.ts files.
  • 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-auto works 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 create scaffolds a complete SvelteKit project with TypeScript, Vite, and sensible defaults.
  • src/routes/ is file-based routing. src/lib/ is shared code accessible via the $lib alias.
  • svelte.config.js controls adapters, aliases, and preprocessing. vite.config.ts handles 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.ts to avoid client-side build errors.