This episode dissects SvelteKit's architecture: filesystem routing, load functions, server routes, and endpoint lifecycle, plus the role of Vite and adapters in the build process. You will also learn project structure, nested layouts, server load versus client load, and hooks and runtime configuration.

In episode 1 you understood why SvelteKit exists. Now it's time to dissect how things work under the hood. Episode 2 builds your mental model of SvelteKit's architecture: how a single src/routes directory turns into a full-stack application, how data flows from the server to components, and how the build process works.
This mental model is the foundation for all subsequent episodes. If you understand the role of every file and the data flow, debugging and adjusting code becomes much easier. Let's dissect it layer by layer.
In SvelteKit, every +page.svelte file inside src/routes becomes a page whose URL follows its folder position. There's no separate routing configuration; folders are the URL structure, files are the content.
src/routes/
|-- about/
| |-- +page.svelte -> /about
|-- blog/
| |-- [slug]/
| | |-- +page.svelte -> /blog/apa-saja
|-- +page.svelte -> /The [slug] convention in a folder name marks a dynamic segment: the value in the URL will be available as params.
Before a page is rendered, SvelteKit runs load functions. On the server, fetched data can be used for SSR; on the client, the result is available to the component through the data prop. The lifecycle is simple: find the +page.server.js or +page.js file, run load, send its result to +page.svelte.
SvelteKit is built on top of Vite. When you run npm run build, Vite compiles all the code, SvelteKit computes routes and prerendering, then the adapter tailors the output to the target platform. The adapter is the only part that differs between platforms.
A standard SvelteKit project always has a few parts:
src/routes — all pages and endpoints of the application.src/lib — shared code across components, importable with the $lib alias.src/routes/api — the conventional place for API endpoints via +server.js files.static — raw assets copied as-is into the output.svelte.config.js — SvelteKit and adapter configuration.vite.config.js — Vite configuration.Files starting with + have special roles: +page.svelte for pages, +layout.svelte for layouts, +server.js for endpoints, and +error.svelte for error pages. Other files inside a route folder are not routed.
Layouts wrap pages. src/routes/+layout.svelte applies to the entire application, while src/routes/blog/+layout.svelte only applies to pages under /blog. This way, shared UI like a navbar can be split per application section.
<script>
let { children } = $props();
</script>
<nav>Navbar bersama</nav>
{@render children()}The children prop in a layout is rendered with {@render children()} to display the wrapped page content.
If several routes in one folder need different layouts, use route groups with parenthesized folder names. Meanwhile, a layout reset (+layout@.svelte) ignores the parent layout and starts from the root, which is useful for pages like login that shouldn't show the navbar.
The +page.server.js file runs on the server: it's a good fit for database access, secrets, and redirects before rendering. The returned data is serialized to the client.
export const load = async (event) => {
const artikel = await ambilDariDatabase();
return { artikel };
};In the server version of load, you have access to event.cookies, event.locals, and event.fetch, which run on the server.
The +page.js file (without .server) runs on the client after JavaScript loads, and also on the server during SSR. Use this when the data isn't sensitive and you want subsequent navigations to feel instant.
The rule of thumb: if the data needs secrets, a database, or a session-based redirect, use +page.server.js. If the data is public and can be cached on the client, use +page.js.
Hooks are global functions that slip into every request. The most commonly used one is handle, which runs before the route is processed — the ideal place for authentication and modifying event.locals.
export const handle = async ({ event, resolve }) => {
return await resolve(event);
};The handle function receives event and resolve; resolve(event) continues the request to the target route. Without calling it, no page gets rendered.
Runtime configuration such as SSR mode, prerender, and adapter is set in svelte.config.js and per-route through exports like export const prerender = true. The combination of both gives you full control without one massive config file.
Key takeaways:
src/routes determine URLs.+ have special roles; regular files in a route folder are not routed.+page.server.js runs on the server, +page.js on the client.handle are global middleware for every request.In the next episode we'll start a SvelteKit project — creating your first app with npm create svelte@latest, getting to know the folder structure and initial configuration, running the dev server with hot module replacement, and setting up TypeScript, ESLint, and Prettier.