or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-server.mdapp-state-navigation.mdapp-state.mdconfiguration.mderror-handling.mdform-actions.mdhooks.mdindex.mdload-functions.mdnodejs-integration.mdrequest-handling.mdresponse-creation.mdservice-worker.mdvite-integration.md

load-functions.mddocs/

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