install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/svelte-load-functions" ~/.claude/skills/intense-visions-harness-engineering-svelte-load-functions && rm -rf "$T"
manifest:
agents/skills/claude-code/svelte-load-functions/SKILL.mdsource content
Svelte Load Functions
Fetch route data before rendering using SvelteKit's load functions — server-only, universal, streaming, and invalidation patterns
When to Use
- You need to fetch data before a page renders (and show it server-side)
- You are choosing between
(universal) and+page.ts
(server-only)+page.server.ts - You need access to database clients, cookies, or session data in your load function
- You want to stream slow data to the browser without blocking the initial render
- You need to invalidate and re-fetch data after a form action or user interaction
Instructions
Server load (+page.server.ts):
- Use
when you need secrets, database access, cookies, or server-only APIs. This function never runs in the browser:+page.server.ts
// src/routes/users/[id]/+page.server.ts import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ params, locals, cookies }) => { const user = await locals.db.user.findUnique({ where: { id: params.id }, }); if (!user) throw error(404, 'User not found'); return { user }; };
- Access the authenticated session via
(set inlocals
):hooks.server.ts
export const load: PageServerLoad = async ({ locals }) => { if (!locals.user) redirect(303, '/login'); return { user: locals.user }; };
Universal load (+page.ts):
- Use
for load functions that can run on both server (initial request) and client (navigation). Use the provided+page.ts
— it is enhanced by SvelteKit for deduplication and credentials:fetch
// src/routes/posts/+page.ts import type { PageLoad } from './$types'; export const load: PageLoad = async ({ fetch, params }) => { const res = await fetch(`/api/posts?page=${params.page ?? 1}`); const posts = await res.json(); return { posts }; };
Accessing load data in the page:
- Receive
as a prop (Svelte 5 withdata
) or as$props
(Svelte 4):export let data
<!-- +page.svelte --> <script lang="ts"> import type { PageData } from './$types' let { data }: { data: PageData } = $props() </script> {#each data.posts as post} <article>{post.title}</article> {/each}
Error handling:
- Throw
orerror
fromredirect
to trigger the error page or redirect:@sveltejs/kit
import { error, redirect } from '@sveltejs/kit'; export const load: PageServerLoad = async ({ params }) => { const post = await getPost(params.slug); if (!post) throw error(404, { message: 'Post not found' }); if (post.status === 'draft') redirect(303, '/'); return { post }; };
Layout loads:
- Add a
to provide data to all pages in a route segment. Layout data is merged with page data:+layout.server.ts
// src/routes/(app)/+layout.server.ts export const load: LayoutServerLoad = async ({ locals }) => { return { currentUser: locals.user }; };
Streaming with promises:
- Return a promise for slow data to stream it to the client without blocking the initial render. Wrap the slow part in
:{#await}
// +page.server.ts export const load: PageServerLoad = async ({ params }) => { // fast — included in initial HTML const product = await getProduct(params.id); // slow — streamed after initial render const reviews = getReviews(params.id); // not awaited return { product, reviews }; };
<!-- +page.svelte --> {#await data.reviews} <p>Loading reviews...</p> {:then reviews} {#each reviews as review}<Review {review} />{/each} {/await}
Invalidation:
- Use
to declare a custom dependency; calldepends('app:tag')
to re-run the load function:invalidate('app:tag')
// load function export const load: PageLoad = async ({ fetch, depends }) => { depends('app:cart'); const cart = await fetch('/api/cart').then((r) => r.json()); return { cart }; }; // After updating cart: import { invalidate } from '$app/navigation'; await invalidate('app:cart');
- Use
to re-run all load functions on the current page.invalidateAll()
Details
Server vs. universal load — decision matrix:
| Need | Use |
|---|---|
| Database access | |
| Cookies / session | |
| Secret env vars | |
| Works without JS | |
| Runs on CDN edge | |
| Client-side navigation data | |
| Public API, no secrets | Either |
Data merging:
When a route has both
+layout.server.ts and +page.server.ts, SvelteKit merges the returned data. If both return a key with the same name, the page-level value wins.
Type generation:
SvelteKit generates types for
PageData, PageServerLoad, LayoutLoad, and LayoutServerLoad in .svelte-kit/types/. Always import from ./$types to get the correct inferred types.
The
function:parent
Load functions can await parent layout data via
parent():
export const load: PageLoad = async ({ parent }) => { const { user } = await parent(); return { greeting: `Hello, ${user.name}` }; };
Fetch in load vs. $fetch:
Always use the
fetch provided by SvelteKit's load function — it:
- Includes credentials (cookies) when fetching same-origin
- Deduplicates identical requests within the same render cycle
- Works correctly on both server and client
Do not use the global
fetch directly inside load functions.
Source
https://kit.svelte.dev/docs/load
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.