0
# Load Functions
1
2
SvelteKit load functions provide a way to fetch data for pages and layouts on both server and client. They run before a page is rendered and can run on the server during SSR or on the client during navigation.
3
4
## Capabilities
5
6
### Universal Load Functions
7
8
Universal load functions run on both server and client and have access to a `LoadEvent`.
9
10
```typescript { .api }
11
/**
12
* Universal load function that runs on both server and client
13
* @param event - LoadEvent containing params, url, fetch, and other utilities
14
* @returns Data object or promise of data object for the page/layout
15
*/
16
type Load<
17
Params = Record<string, string>,
18
InputData = Record<string, any> | null,
19
ParentData = Record<string, any>,
20
OutputData = Record<string, any> | void
21
> = (event: LoadEvent<Params, InputData, ParentData>) => Promise<OutputData> | OutputData;
22
23
interface LoadEvent<
24
Params = Record<string, string>,
25
Data = Record<string, any> | null,
26
ParentData = Record<string, any>
27
> {
28
/** Route parameters extracted from the URL */
29
params: Params;
30
/** The current URL */
31
url: URL;
32
/** Route information */
33
route: { id: string };
34
/** Enhanced fetch function with server-side benefits */
35
fetch: typeof fetch;
36
/** Data from the corresponding .server.js file (if any) */
37
data: Data;
38
/** Access to parent layout data */
39
parent: () => Promise<ParentData>;
40
/** Declare dependencies for cache invalidation */
41
depends: (...deps: string[]) => void;
42
/** Set response headers (server-side only) */
43
setHeaders: (headers: Record<string, string>) => void;
44
/** Opt out of dependency tracking */
45
untrack: <T>(fn: () => T) => T;
46
}
47
```
48
49
**Usage Examples:**
50
51
```typescript
52
// src/routes/blog/[slug]/+page.js
53
export async function load({ params, fetch, depends }) {
54
// Declare dependencies for cache invalidation
55
depends('blog:post');
56
57
const response = await fetch(`/api/posts/${params.slug}`);
58
59
if (!response.ok) {
60
throw error(404, 'Post not found');
61
}
62
63
const post = await response.json();
64
65
return {
66
post,
67
meta: {
68
title: post.title,
69
description: post.excerpt
70
}
71
};
72
}
73
```
74
75
### Server Load Functions
76
77
Server load functions run only on the server and have access to additional server-only features like cookies and platform.
78
79
```typescript { .api }
80
/**
81
* Server load function that runs only on the server
82
* @param event - ServerLoadEvent extending RequestEvent with load-specific utilities
83
* @returns Data object or promise of data object for the page/layout
84
*/
85
type ServerLoad<
86
Params = Record<string, string>,
87
ParentData = Record<string, any>,
88
OutputData = Record<string, any> | void
89
> = (event: ServerLoadEvent<Params, ParentData>) => Promise<OutputData> | OutputData;
90
91
interface ServerLoadEvent<
92
Params = Record<string, string>,
93
ParentData = Record<string, any>
94
> extends RequestEvent<Params> {
95
/** Access to parent layout data */
96
parent: () => Promise<ParentData>;
97
/** Declare dependencies for cache invalidation */
98
depends: (...deps: string[]) => void;
99
}
100
```
101
102
**Usage Examples:**
103
104
```typescript
105
// src/routes/dashboard/+page.server.js
106
import { redirect } from '@sveltejs/kit';
107
108
export async function load({ locals, cookies, url }) {
109
// Check authentication
110
if (!locals.user) {
111
throw redirect(303, '/login');
112
}
113
114
// Server-side database access
115
const projects = await db.projects.findMany({
116
where: { userId: locals.user.id }
117
});
118
119
// Set cache headers
120
setHeaders({
121
'Cache-Control': 'private, max-age=300'
122
});
123
124
return {
125
user: locals.user,
126
projects,
127
preferences: JSON.parse(cookies.get('preferences') || '{}')
128
};
129
}
130
```
131
132
## Load Function Patterns
133
134
### Basic Page Load
135
136
```typescript
137
// src/routes/products/[id]/+page.js
138
export async function load({ params, fetch }) {
139
const [productRes, reviewsRes] = await Promise.all([
140
fetch(`/api/products/${params.id}`),
141
fetch(`/api/products/${params.id}/reviews`)
142
]);
143
144
if (!productRes.ok) {
145
throw error(404, 'Product not found');
146
}
147
148
const product = await productRes.json();
149
const reviews = reviewsRes.ok ? await reviewsRes.json() : [];
150
151
return {
152
product,
153
reviews
154
};
155
}
156
```
157
158
### Layout Load with Parent Data
159
160
```typescript
161
// src/routes/admin/+layout.server.js
162
export async function load({ locals, depends }) {
163
// Ensure admin access
164
if (!locals.user?.isAdmin) {
165
throw redirect(303, '/');
166
}
167
168
depends('admin:stats');
169
170
const stats = await getAdminStats();
171
172
return {
173
adminUser: locals.user,
174
stats
175
};
176
}
177
178
// src/routes/admin/users/+page.js
179
export async function load({ parent, fetch }) {
180
const { adminUser } = await parent();
181
182
const users = await fetch('/api/admin/users').then(r => r.json());
183
184
return {
185
users,
186
canManageUsers: adminUser.permissions.includes('manage_users')
187
};
188
}
189
```
190
191
### Conditional Loading
192
193
```typescript
194
// src/routes/search/+page.js
195
export async function load({ url, fetch, depends }) {
196
const query = url.searchParams.get('q');
197
198
if (!query) {
199
return { results: [], query: '' };
200
}
201
202
depends(`search:${query}`);
203
204
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
205
const results = await response.json();
206
207
return {
208
results,
209
query
210
};
211
}
212
```
213
214
### Error Handling in Load Functions
215
216
```typescript
217
// src/routes/posts/[slug]/+page.server.js
218
export async function load({ params, fetch }) {
219
try {
220
const response = await fetch(`/api/posts/${params.slug}`);
221
222
if (response.status === 404) {
223
throw error(404, {
224
message: 'Post not found',
225
slug: params.slug
226
});
227
}
228
229
if (!response.ok) {
230
throw error(500, 'Failed to load post');
231
}
232
233
const post = await response.json();
234
235
// Check if post is published
236
if (!post.published && !locals.user?.isAdmin) {
237
throw error(403, 'Post not published');
238
}
239
240
return { post };
241
} catch (err) {
242
if (err.status) throw err; // Re-throw SvelteKit errors
243
244
console.error('Load error:', err);
245
throw error(500, 'Internal server error');
246
}
247
}
248
```
249
250
### Streaming and Parallel Loading
251
252
```typescript
253
// src/routes/dashboard/+layout.server.js
254
export async function load({ locals }) {
255
// Load critical data immediately
256
const user = locals.user;
257
258
// Stream non-critical data
259
const analyticsPromise = loadAnalytics(user.id);
260
const notificationsPromise = loadNotifications(user.id);
261
262
return {
263
user,
264
// These promises will be resolved by the client
265
analytics: analyticsPromise,
266
notifications: notificationsPromise
267
};
268
}
269
```
270
271
## Advanced Load Patterns
272
273
### Dependency Management
274
275
```typescript
276
// src/routes/blog/+page.js
277
export async function load({ fetch, depends, url }) {
278
const page = parseInt(url.searchParams.get('page') || '1');
279
const category = url.searchParams.get('category');
280
281
// Track dependencies for cache invalidation
282
depends('blog:posts');
283
if (category) depends(`blog:category:${category}`);
284
285
const posts = await fetch(`/api/posts?page=${page}&category=${category || ''}`)
286
.then(r => r.json());
287
288
return { posts, page, category };
289
}
290
291
// Invalidate from elsewhere:
292
// import { invalidate } from '$app/navigation';
293
// await invalidate('blog:posts');
294
```
295
296
### Untracked Operations
297
298
```typescript
299
export async function load({ url, untrack, fetch }) {
300
// This won't trigger reloads when URL changes
301
const theme = untrack(() => url.searchParams.get('theme')) || 'light';
302
303
const data = await fetch('/api/data').then(r => r.json());
304
305
return { data, theme };
306
}
307
```
308
309
### Progressive Enhancement
310
311
```typescript
312
// src/routes/search/+page.server.js
313
export async function load({ url }) {
314
const query = url.searchParams.get('q');
315
316
if (!query) {
317
return { results: [], query: '' };
318
}
319
320
// Server-side search for initial page load
321
const results = await searchDatabase(query);
322
323
return {
324
results,
325
query,
326
serverRendered: true
327
};
328
}
329
330
// src/routes/search/+page.js
331
export async function load({ data, fetch, url }) {
332
// If we have server data, use it
333
if (data.serverRendered) {
334
return data;
335
}
336
337
// Client-side search for navigation
338
const query = url.searchParams.get('q');
339
if (!query) return { results: [], query: '' };
340
341
const results = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
342
.then(r => r.json());
343
344
return { results, query };
345
}
346
```
347
348
## Load Function Utilities
349
350
### Using Fetch
351
352
The `fetch` function in load functions has enhanced capabilities:
353
354
```typescript
355
export async function load({ fetch }) {
356
// Inherits cookies and headers from the page request
357
const response = await fetch('/api/user/profile');
358
359
// Can make relative requests on the server
360
const posts = await fetch('/api/posts').then(r => r.json());
361
362
// Internal requests go directly to handlers
363
const internal = await fetch('/api/internal').then(r => r.json());
364
365
return { profile: await response.json(), posts, internal };
366
}
367
```
368
369
### Setting Headers
370
371
```typescript
372
// src/routes/api-docs/+page.server.js
373
export async function load({ setHeaders, fetch }) {
374
const docs = await fetch('/api/docs').then(r => r.json());
375
376
// Cache for 1 hour
377
setHeaders({
378
'Cache-Control': 'public, max-age=3600',
379
'Vary': 'Accept-Encoding'
380
});
381
382
return { docs };
383
}
384
```
385
386
## Best Practices
387
388
1. **Use server load for sensitive data**: Database queries, API keys, user sessions
389
2. **Use universal load for public data**: Data that can be safely exposed to the client
390
3. **Handle errors appropriately**: Use `error()` for user-facing errors, log unexpected errors
391
4. **Minimize waterfalls**: Use `Promise.all()` for parallel requests
392
5. **Use dependencies wisely**: Only depend on data that should trigger reloads
393
6. **Consider caching**: Set appropriate cache headers for static data
394
7. **Keep load functions fast**: Users expect pages to load quickly
395
8. **Use parent() efficiently**: Call `parent()` after your own data fetching to avoid waterfalls