Project Structure
What lives in src/routes, src/lib, and static — and why the separation matters.
អាន 2 នាទី
A SvelteKit project has three directories that matter more than any other: src/routes, src/lib, and static. Knowing what belongs in each — and why — saves you from fighting the framework later.
src/routes: your app's URLs
Everything under src/routes is part of the router. The folder structure is the URL structure, and files prefixed with + have special meaning:
src/routes/
├── +page.svelte → /
├── +layout.svelte → wraps every page below it
├── about/
│ └── +page.svelte → /about
└── blog/
├── +page.svelte → /blog
└── [slug]/
└── +page.svelte → /blog/hello-world, /blog/anything
Because this folder is scanned to build your routes, it's not the place for shared utilities, components you reuse across pages, or anything that isn't itself a route. Putting a Button.svelte directly in src/routes/ works, technically — but it clutters the one directory that's supposed to mirror your URLs, and it's easy to accidentally create a route by naming a file +page.svelte by mistake.
src/lib: everything else
src/lib is for shared code: components, utilities, stores, types. SvelteKit gives it a special import alias, $lib, so you never write fragile relative paths like ../../../lib/utils:
<script>
import Button from '$lib/components/Button.svelte';
import { formatDate } from '$lib/utils/date';
</script>$lib always resolves to src/lib, no matter how deeply nested the file importing it is. A common layout:
src/lib/
├── components/
│ ├── Button.svelte
│ └── Header.svelte
├── server/ # code that must never reach the browser
│ └── db.js
└── utils/
└── date.js
That server/ subfolder is worth calling out: anything imported only from +page.server.js, +server.js, or hooks.server.js files never gets bundled for the client, so it's safe to put database clients or secret-using code there. SvelteKit also enforces this with a special $lib/server alias that throws a build error if client code accidentally imports from it.
static: files served as-is
static/
├── favicon.png
├── robots.txt
└── og-image.jpg
Anything in static/ is copied verbatim to the root of your deployed site with no processing — static/favicon.png becomes /favicon.png. Use it for files that need a fixed, predictable URL: favicons, robots.txt, manifest files, or images referenced directly by URL rather than imported into a component.
Contrast this with an image imported inside a .svelte file (import hero from '$lib/images/hero.jpg') — Vite processes those, hashing the filename for cache-busting and optimizing them as part of the build. Use static/ when the exact path matters; import everything else.
Why the separation pays off
Keeping routes, shared code, and static assets separate isn't just tidiness — the router only scans src/routes, so keeping non-route files out of it keeps your URL structure honest and predictable as the app grows. The next lesson digs into exactly how folder names inside src/routes translate into URL patterns, including dynamic segments like [slug].