Loading Data
SvelteKit separates data loading from rendering. Load functions run before the page renders.
Universal Load (+page.ts)
Runs on both server (initial request) and client (navigation):
// src/routes/blog/[slug]/+page.ts
export async function load({ params, fetch }) {
const res = await fetch(`/api/posts/${params.slug}`);
const post = await res.json();
return { post };
}
Access in the component:
<!-- +page.svelte -->
<script>
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<p>{data.post.content}</p>
Server Load (+page.server.ts)
Runs only on the server. Use for database queries, secrets, or heavy computation:
// src/routes/dashboard/+page.server.ts
import { db } from '$lib/server/db';
export async function load({ locals }) {
const user = locals.user;
const stats = await db.getStats(user.id);
return { stats };
}
Gotcha: Data returned from server load functions is serialized to JSON. You can’t return class instances, functions, or Maps - only plain objects, arrays, and primitives.
When to Use Which
Use +page.ts | Use +page.server.ts |
|---|---|
| Public API calls | Database queries |
Data from fetch() | Access to secrets/env vars |
| Runs on client navigation too | File system access |
Can use SvelteKit’s fetch (with cookies) | Heavy computation |
Error Handling
import { error } from '@sveltejs/kit';
export async function load({ params }) {
const post = await getPost(params.slug);
if (!post) {
error(404, { message: 'Post not found' });
}
return { post };
}
Redirects
import { redirect } from '@sveltejs/kit';
export async function load({ locals }) {
if (!locals.user) {
redirect(303, '/login');
}
}