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().

File layout
src/ui/
└── pages/
    └── projects/
        ├── detail.svelte          # Page component
        └── detail.load.ts         # Server data for detail.svelte
src/ui/pages/projects/detail.load.ts
// 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
<!-- 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
<!-- 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.

NoEgo

© 2025 NoEgo. All rights reserved.