02 - Project Setup & Structure

📋 Jump to Takeaways

Creating a Project

npx sv create my-app
cd my-app
npm install
npm run dev

npm run dev starts a local server at http://localhost:5173. Changes auto-reload.

Project Structure

After creating a project, you'll see:

my-app/
├── src/
│   ├── routes/              ← Your pages live here
│   │   ├── +page.svelte     ← Home page (/)
│   │   └── +layout.svelte   ← Root layout (wraps all pages)
│   ├── lib/                 ← Your reusable code
│   │   ├── components/      ← Shared components
│   │   └── server/          ← Server-only code (DB, secrets) — PROTECTED
│   ├── app.html             ← HTML shell (you rarely edit this)
│   ├── hooks.server.ts      ← Server hooks (auth, logging)
│   └── hooks.client.ts      ← Client hooks (optional — only for global error handling)
├── static/                  ← Static files (favicon, images)
├── svelte.config.js         ← SvelteKit config
├── vite.config.ts           ← Vite bundler config
├── tsconfig.json            ← TypeScript config
└── package.json

The Two Most Important Folders

Your Pages - src/routes/

This is where you spend most of your time. Each folder = a URL:

src/routes/
├── +page.svelte              → /           (home page)
├── +layout.svelte            → wraps all pages (nav, footer)
├── +layout.server.ts         → loads data for the layout (server-only, e.g. auth user)
├── about/
│   └── +page.svelte          → /about
├── blog/
│   └── +page.svelte          → /blog
└── contact/
    └── +page.svelte          → /contact

Your Reusable Code - src/lib/

Components, utilities, types, stores — anything shared across pages. Import using the $lib alias:

<!-- Instead of: import Card from '../../../lib/components/Card.svelte' -->
<script>
import Card from '$lib/components/Card.svelte';
</script>

$lib always points to src/lib/ no matter where you import from.

$lib is one of several built-in aliases SvelteKit provides. Here's the full list:

Alias What it is Example
$lib Your shared code (src/lib/) import Card from '$lib/components/Card.svelte'
$lib/server Server-only code (never sent to browser) import { db } from '$lib/server/database'
$app/navigation Client-side navigation goto, invalidate, invalidateAll
$app/forms Form enhancement enhance
$app/state Page state (URL, params, errors) page
$app/environment Runtime info browser, dev
$env/static/private Build-time secrets (server only) DATABASE_URL, API_KEY
$env/static/public Build-time public vars PUBLIC_SITE_URL
$env/dynamic/private Runtime secrets (server only) Same as static but read at request time
$env/dynamic/public Runtime public vars Same as static but read at request time

You don't need to memorize these. We'll use them throughout the course. Just know they exist and come back to this table when you need one.

🎯 Note: only $lib maps to a real folder (src/lib/). The $app and $env aliases are virtual modules provided by SvelteKit at build time, you won't find them in your file system.

Protected Server Code - src/lib/server/

src/lib/server/ is a special folder — SvelteKit prevents it from being imported in client-side code. If you try, the build fails. This is where you put database connections, API keys, and any code that must never reach the browser.

Only server-only files can import from it:

  • +page.server.ts, +layout.server.ts, +server.ts, hooks.server.ts
  • +page.svelte, +page.ts ❌ (build error)

The same protection applies to any file with .server in the name. A +page.server.ts is never sent to the browser. It runs on the server, returns data, and SvelteKit passes that data to +page.svelte as serialized JSON. The browser gets the data, not the code.

The rule: if it has server in the name (file or folder), it stays on the server.

Special Files in a Route

Each route folder can have these files (all optional except +page.svelte):

File What it does Runs on
+page.svelte The page UI Browser
+page.ts Loads data for the page Server + Browser
+page.server.ts Loads data (server only) + form actions Server only
+layout.svelte Wraps child pages with shared UI Browser
+layout.ts Loads data for the layout Server + Browser
+layout.server.ts Loads data for layout (server only) Server only
+error.svelte Error page Browser
+server.ts API endpoint (no UI) Server only

Don't memorize this — you'll learn each one in upcoming lessons. For now, just know:

  • .svelte files = UI (what the user sees)
  • .ts files = logic (data loading, form handling, API endpoints)
  • server in the name = runs only on the server (safe for secrets/DB)

Your First Page

Create src/routes/+page.svelte:

<!-- src/routes/+page.svelte -->
<h1>Hello SvelteKit!</h1>
<p>This is the home page.</p>

That's it. Visit http://localhost:5173 and you'll see it. No imports, no configuration.

Adding a Second Page

Create src/routes/about/+page.svelte:

<!-- src/routes/about/+page.svelte -->
<h1>About</h1>
<p>This is the about page.</p>
<a href="/">← Back home</a>

Visit http://localhost:5173/about. Navigation between pages is instant — SvelteKit handles it client-side.

The app.html Shell

src/app.html is the HTML template that wraps everything:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    %sveltekit.head%
  </head>
  <body>
    %sveltekit.body%
  </body>
</html>
  • %sveltekit.head% — SvelteKit injects CSS, meta tags, etc.
  • %sveltekit.body% — SvelteKit injects your rendered page

You rarely need to edit this file.

Next Lesson

Now that you have a project, let's learn how routing works in detail — dynamic routes, parameters, and navigation.

Key Takeaways

  • src/routes/ = pages. Folder structure = URL structure
  • src/lib/ = shared code. Import with $lib/
  • +page.svelte = what the user sees
  • +page.server.ts = server logic (data, forms)
  • npm run dev = start developing

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

© 2026 ByteLearn.dev. Free courses for developers. · Privacy