# Routing
## Define and start a router
```tsx
const router = createRouter({
routes: [
{ path: "/", component: Home, title: "Home" },
{
path: "/users/:id",
component: User,
title: match => `User ${match.params.id}`,
load: async ({ params, signal }) => {
const response = await fetch(`/api/users/${params.id}`, { signal });
return response.json();
},
},
{ path: "/docs/:page?", component: Docs },
{ path: "*", component: NotFound },
],
loading: Loading,
error: LoadError,
});
const stop = router.start();
render(root, );
```
Routes are checked in declaration order. Put a wildcard last.
## Patterns
- `/users/:id` captures one required segment.
- `/docs/:page?` captures an optional segment.
- `/files/*` captures the remainder as `wildcard`.
- `*` matches every path.
Captured values are URI-decoded. `matchPath()` and `matchRoutes()` are exported for server and test use.
## Component props
The matched component receives `{ route, params, query, data }`. Repeated query keys become arrays; a single value remains a string.
## Links and navigation
```tsx
Open user
await router.navigate("/users/42");
await router.navigate("/login", { replace: true, state: { from: "/private" } });
```
Router links render ordinary anchors with `data-clank-link`. Modified clicks, downloads, explicit targets, external origins, and already-prevented events retain native browser behavior.
## Loaders and cancellation
Navigation sets the route to `loading`, passes an `AbortSignal` to its loader, then commits `ready` data. The previous loader is aborted on a newer navigation, and revision checks reject stale results even if the loader ignores abort.
## Guards
```ts
guard: ({ from, params }) => {
if (!session.value) return `/login?next=/projects/${params.id}`;
return true;
}
```
A guard may return `true`, `false`, or a redirect URL, synchronously or asynchronously. `false` cancels navigation. A string recursively navigates with replacement.
## Base paths and non-browser resolution
Set `base: "/app"` when hosted below an origin root. `matchRoutes()` and `resolve(url)` also work without a browser; relative URLs use a safe internal origin.