Load Functions
A load function is a server-side function attached to a Forge page or layout. It runs before that route renders, and the object it returns becomes the props for that component.
You do not call it from the component. Forge finds it from the matched route, runs it automatically on the server, and gives the component the returned data.
Basic Pattern
Put a .load.ts file next to the page with the same base name. Forge runs it automatically on the server and passes the returned object into the page through $props().
src/ui/
└── pages/
└── projects/
├── detail.svelte # Page component
└── detail.load.ts # Server data for detail.svelte// src/ui/pages/projects/detail.load.ts
import { getContainer } from "@noego/ioc";
import ProjectService from "../../../server/services/project_service";
export default async function load({ params }) {
const container = getContainer();
const projectService = container.get(ProjectService);
const project = await projectService.findById(params.id);
return {
project
};
}<!-- src/ui/pages/projects/detail.svelte -->
<script lang="ts">
let { project } = $props();
</script>
<h1>{project.name}</h1>
<p>{project.description}</p>The load file stays server-side. It can resolve backend services, query the database, and use private credentials. The browser only receives the plain object returned from load().
Choose a Data Strategy
Put critical render data in load()
Use load for data the page needs before it can render correctly: user identity, permissions, route records, titles, navigation state, and initial form values.
Fetch secondary data after render
Use normal API calls for slower, interactive, or optional data: activity feeds, analytics, search results, infinite lists, autosave, and user-triggered actions.
Let layouts load shared data
Put app-wide data in a layout load function when many pages need it, such as the signed-in user, sidebar projects, organization settings, or feature flags.
Keep pages without server data simple
If a page does not need backend data before render, skip load. Forge can navigate to that page without waiting for page-specific server data.
What Belongs Where
Good load data
- Current user and account state
- Route record, such as project, team, invoice, or article
- Permissions that change visible actions
- Small lists needed to draw the first screen
- SEO or page title data
Better as an API fetch
- Large tables, histories, logs, and activity streams
- Data that changes after a button click
- Background refreshes and polling
- Search results and filters
- Slow third-party calls that should not block the page
Split Fast Data from Later Data
Load the data that shapes the first screen, then fetch heavier data after mount. This gives users a meaningful page immediately without blocking on everything the page may eventually show.
<!-- src/ui/pages/projects/detail.svelte -->
<script context="module" lang="ts">
export async function load({ params, context }) {
return {
project: await context.projects.find(params.id),
currentUser: context.user,
canEdit: await context.permissions.canEditProject(params.id)
};
}
</script>
<script lang="ts">
import { onMount } from "svelte";
let { project, currentUser, canEdit } = $props();
let activity = $state([]);
onMount(async () => {
activity = await fetch(`/api/projects/${project.id}/activity`).then(r => r.json());
});
</script>
<header>
<p>{currentUser.name}</p>
<h1>{project.name}</h1>
{#if canEdit}<a href={`/projects/${project.id}/settings`}>Settings</a>{/if}
</header>
<ActivityFeed items={activity} />What load() Receives
A load function receives request information from the matched route. Middleware can also add private request context, such as the authenticated user or database services.
- url
- Full request URL.
- params
- Path parameters from the matched OpenAPI route.
- query
- Parsed query string values.
- headers
- Incoming request headers.
- body
- Parsed body for methods that include one.
- context
- Per-request data added by middleware; never serialized to the browser.
How Navigation Feels
On the first visit, load data is available during server render. On in-app navigation, Forge keeps the app experience smooth: routes with load functions ask the server for fresh page data, while routes without load functions can switch immediately. You write the page once; Forge handles both entry points.