Routing

Routes are defined by the folder structure of src/routes. Each folder maps to a URL path, and each file within it handles a part of the request:

/routes
	/+page.ts              → /
	/about/+page.ts        → /about
	/posts/[id]/+page.ts   → /posts/123
	/api/posts/+server.ts  → /api/posts

Special files

  • +page.ts — the page endpoint: the component to render, plus an optional client load function
  • +page.server.ts — a server-only load function and form actions
  • +server.ts — a plain HTTP endpoint (no UI) — see API Endpoints
  • _layout.ts and _layout.server.ts — wrap every route in the folder and the folders below it
  • _error.ts — the page shown when a request in the folder fails
  • _hook.server.ts — runs before and after every request below it — see Hooks

Pages

A +page.ts exports the component to render, imported from src/views (or wherever you keep your components):


// routes/posts/[id]/+page.ts
import component from "@/views/Post.torp";
import { type PageEndPoint } from "@torpor/build";

export default {
	component,
} satisfies PageEndPoint;

Annotate the endpoint with its route path to get typed params in load functions and URL builders, e.g. PageEndPoint<"/posts/[id]">.

Dynamic segments

Use square brackets for dynamic segments: [id] matches a single path segment, and [...path] matches the rest of the path. The values are passed to load functions and actions as strings via event.params.

Type-safe URLs

Build URLs with route instead of string concatenation. Params are checked at compile time and missing or unknown params are errors:


import { route } from "@torpor/build/nav";

route("/posts/[id]", { id: 5 }); // "/posts/5"
route("/posts/[id]"); // compile error: missing 'id'

Routes in code

For small sites, routes can be added in code instead of using the standard file names. Each option maps to a file route type, and inline server code is kept out of the client bundle automatically:


import { Site, ok } from "@torpor/build";

const site = new Site();

site.addRoute("/", {
	page: "./src/Counter.torp",
	pageServer: { actions: { set: async ({ request }) => ok() } },
});

site.addRoute("/api/time", {
	server: { get: async () => ok({ time: Date.now() }) },
});