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-routing-pattern" ~/.claude/skills/intense-visions-harness-engineering-svelte-routing-pattern && rm -rf "$T"
manifest:
agents/skills/claude-code/svelte-routing-pattern/SKILL.mdsource content
Svelte Routing Pattern
Build SvelteKit routes using the file-system convention with +page.svelte, +layout.svelte, route groups, and dynamic segments
When to Use
- You are adding new routes to a SvelteKit application
- You need to understand how
,+page.svelte
, and their server counterparts relate+layout.svelte - You need dynamic route segments (e.g.,
), catch-all routes, or optional params/users/[id] - You want to share layout UI (nav, sidebar) across a group of routes without affecting the URL
Instructions
Basic file structure:
- Every route is a directory in
. Thesrc/routes/
file renders the page content:+page.svelte
src/routes/ +page.svelte → / +layout.svelte → wraps all pages about/ +page.svelte → /about blog/ +page.svelte → /blog [slug]/ +page.svelte → /blog/:slug
- Create a layout by adding
— it wraps all sibling and descendant pages. Use+layout.svelte
to render child content:<slot />
<!-- src/routes/+layout.svelte --> <script lang="ts"> import Nav from '$lib/components/Nav.svelte' let { children } = $props() </script> <Nav /> <main> {@render children()} </main>
Dynamic segments:
- Use
for dynamic route segments. Read them via[param]
or from the load function:$page.params
routes/ users/ [id]/ +page.svelte → /users/:id +page.server.ts → server load for this route
<!-- +page.svelte --> <script lang="ts"> import { page } from '$app/stores' const userId = $page.params.id </script>
- Use
for catch-all segments that match one or more path parts:[...rest]
routes/ docs/ [...path]/ +page.svelte → /docs/a/b/c — params.path = 'a/b/c'
- Use
for optional segments:[[optional]]
routes/ [[lang]]/ +page.svelte → / and /:lang both match
Route groups — layout without URL impact:
- Wrap routes in parentheses to create a group that shares a layout without affecting the URL:
routes/ (marketing)/ +layout.svelte → marketing layout +page.svelte → / about/ +page.svelte → /about (app)/ +layout.svelte → app layout with auth check dashboard/ +page.svelte → /dashboard
Navigation:
- Use
tags for client-side navigation — SvelteKit intercepts them automatically. Use<a>
for programmatic navigation:goto
<script lang="ts"> import { goto } from '$app/navigation' async function handleSubmit() { await submitForm() goto('/dashboard') } </script> <a href="/about">About</a>
- Preload data on hover using the
attribute:data-sveltekit-preload-data
<a href="/expensive-page" data-sveltekit-preload-data="hover">Load on hover</a>
Named layouts (breaking out of parent layouts):
- Reset the layout inheritance by naming the layout file
or using the+layout-reset.svelte
syntax for matching a specific ancestor:@
routes/ +layout.svelte → root layout admin/ +layout.svelte → admin layout +layout@.svelte → reset: only uses root layout
Details
File naming reference:
| File | Purpose |
|---|---|
| Page UI component |
| Universal load (client + server) |
| Server-only load + form actions |
| Layout wrapper with |
| Universal layout load |
| Server-only layout load |
| Error boundary for the route |
| API endpoint (no UI) |
Data flow:
Parent layout
load() runs before child page load(). Data from a layout load is available to all descendant pages. Data does not flow upward.
$page store:
The
$page store from $app/stores provides reactive access to the current route:
import { page } from '$app/stores'; $page.url; // URL object $page.params; // route params $page.data; // merged data from all load functions $page.status; // HTTP status $page.error; // error object if on error page
Nested layouts and data isolation:
Each layout can have its own load function. The
data prop in a layout component only receives data from that layout's load — not child page data. Use $page.data to read the full merged data object.
API routes:
Use
+server.ts for routes that return JSON or other non-HTML responses:
// src/routes/api/users/+server.ts import { json } from '@sveltejs/kit'; export const GET = async ({ locals }) => { const users = await locals.db.users.findMany(); return json(users); };
Source
https://kit.svelte.dev/docs/routing
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.