Skip to content

Server Loaders

Server loaders run on every request to fetch data for pages and layouts.

Export a load function from +page.server.ts:

import type { LoadEvent } from "bosia";
export async function load({ params, url, locals, cookies }: LoadEvent) {
const post = await db.getPost(params.slug);
return { post };
}

The returned object becomes the data prop in +page.svelte:

<script lang="ts">
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<p>{data.post.content}</p>

+layout.server.ts works the same way but its data is available to all child routes:

src/routes/+layout.server.ts
import type { LoadEvent } from "bosia";
export async function load({ locals }: LoadEvent) {
return {
appName: "Bosia Demo",
requestTime: locals.requestTime,
};
}

Child loaders can access data from parent layout loaders:

src/routes/blog/[slug]/+page.server.ts
import type { LoadEvent } from "bosia";
export async function load({ params, parent }: LoadEvent) {
const parentData = await parent();
const post = await db.getPost(params.slug);
return {
post,
appName: parentData.appName, // from root layout loader
};
}

Data flows top-down: root layout → group layout → page layout → page.

Export a metadata function to set page title and meta tags:

import type { MetadataEvent, LoadEvent } from "bosia";
export function metadata({ params }: MetadataEvent) {
const post = getPost(params.slug);
return {
title: `${post.title} — My Blog`,
description: `A blog post about ${params.slug}`,
meta: [
{ property: "og:title", content: post.title },
],
// Pass data to load() — avoids duplicate queries
data: { post },
};
}
export async function load({ params, parent, metadata }: LoadEvent) {
const parentData = await parent();
// Reuse data from metadata() — no duplicate DB query
const post = metadata?.post ?? getPost(params.slug);
return { post, appName: parentData.appName };
}

The data property in metadata() return value is passed to load() as event.metadata. This lets you fetch data once and share it between both functions.

PropertyTypeDescription
urlURLThe request URL
paramsRecord<string, string>Dynamic route parameters
localsRecord<string, any>Data set by middleware hooks
cookiesCookiesRead/write cookies
fetchFunctionSession-aware fetch (forwards cookies)
parent() => Promise<Record>Data from parent layout loaders
metadataRecord | nullData passed from metadata() function

Throw errors from loaders to show the error page:

import { error, redirect } from "bosia";
export async function load({ params }: LoadEvent) {
const post = await db.getPost(params.slug);
if (!post) {
error(404, "Post not found");
}
if (post.isPrivate) {
redirect(303, "/login");
}
return { post };
}

Loaders have configurable timeouts to prevent hung responses:

Env VariableDefaultDescription
LOAD_TIMEOUTTimeout for load() in ms
METADATA_TIMEOUTTimeout for metadata() in ms