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.tsUse +page.server.ts
Public API callsDatabase queries
Data from fetch()Access to secrets/env vars
Runs on client navigation tooFile 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');
  }
}