# Routing

> Define typed routes, layouts, navigation, loaders, policies, and metadata.

Source: [https://askrjs.com/docs/routing](https://askrjs.com/docs/routing)

Status: stable. Packages: @askrjs/askr/router.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Register a route once and let the same registry drive browser navigation, SSR, and static generation.

```tsx
import { createRouteRegistry, group, route } from '@askrjs/askr/router';

export const registry = createRouteRegistry(() => {
  group({ layout: AppLayout }, () => {
    route('/', HomePage);
  route('/projects/{projectId}', ProjectPage);
  });
});
```

## Published props

Generated from the TypeScript declarations shipped by the installed package.

### `LinkProps`

Import from `@askrjs/askr/router`.

- `aria-current?: "page" | "step" | "location" | "date" | "time" | "true" | "false" | undefined;` — Optional aria-current attribute for indicating current page/location.
Use "page" for the current page in navigation.
- `aria-label?: string | undefined;` — Optional aria-label for accessibility when link text isn't descriptive enough.
- `children?: RenderableChild;`
- `class?: string | undefined;`
- `href?: string | undefined;`
- `onClick?: ((event: MouseEvent) => void) | undefined;`
- `onPress?: ((event: Event) => void) | undefined;`
- `rel?: string | undefined;` — Optional rel attribute for link relationships.
Common values: "noopener", "noreferrer", "nofollow"
- `target?: string | undefined;` — Optional target attribute.
Use "_blank" for new tab/window.
- `to?: RouteDestination | undefined;`

### `ResolveProps`

Import from `@askrjs/askr/router`.

- `children: (value: T) => RenderableChild;`
- `pending?: RenderableChild;`
- `rejected?: RenderableChild | ((error: unknown) => RenderableChild);`
- `value: Deferred<T>;`

## Route registry

Every route in an Askr app is declared through `createRouteRegistry()`, which takes a definition function and returns a `RouteRegistry` built by calling `route()`, `page()`, `group()`, `index()`, and `fallback()` inside that function. The registry is an ordinary value: export it, then hand it to `createSPA`, `hydrateSPA`, `createStaticGen`, or `renderToString`, so client rendering, hydration, SSG, and SSR all read the same declaration. Because nothing is stored globally, two registries can coexist — which is what lets a static build settle its own route tree without disturbing the one the browser boots from, and what keeps a server rendering concurrent requests off shared mutable state.

## Route groups

`group(options, fn)` nests a block of route declarations under a shared layout and shared access rules without repeating them on every child route. The `layout` you pass in `GroupHelperOptions` wraps whatever the group renders, and `auth`/`policies` on the group apply to every route declared inside its callback. Groups compose: nesting one group inside another builds up a `layoutChain` and a merged set of policies that Askr walks top-down when it resolves a request, so a route three groups deep still only needs to declare what's specific to it.

## Navigation lifecycle

A navigation in Askr resolves through `resolveRouteRequest()`, which matches the target against the app's explicit `RouteRegistry` and returns either a `RouteRenderResult`, an `AccessRedirectDecision`, an `AccessDenyDecision`, or `null` if nothing matches. That result already reflects any policy checks — redirects and denials are decided before a component ever renders, not caught afterward. Each `RouteContext` handed through the pipeline carries an `AbortSignal`, so loaders and preload functions tied to a route that gets superseded by a newer navigation can be cancelled instead of racing to finish and clobber the current view.

## Delivery modes

`RouteMode` is one of `'spa'`, `'ssr'`, or `'ssg'`, and it's threaded through `RouteContext` so a loader or a policy can behave differently depending on how the current request is being served. The same route declarations work across all three modes — you don't write separate route trees for server rendering versus the client. SSG specifically leans on the `entries` option in `RouteOptions`, which returns the list of param combinations to pre-render as static pages at build time.

## In this section

- [Definitions and Layouts](https://askrjs.com/docs/routing/definitions-and-layouts/index.md): Declare routes, nested layouts, and groups in one typed registry you can read and enumerate.
- [Paths, Parameters, and Destinations](https://askrjs.com/docs/routing/paths-and-parameters/index.md): Path params are inferred from the literal route string, so a component gets typed params without hand-written types.
- [Navigation and URL State](https://askrjs.com/docs/routing/navigation-and-url-state/index.md): Navigate with Link and navigate(), and keep URL-owned state in the URL rather than mirroring it into component state.
- [Loaders and Deferred Values](https://askrjs.com/docs/routing/loaders-and-deferred/index.md): Load route data before render, and mark the slow parts deferred so they do not block the first paint.
- [Access Policies](https://askrjs.com/docs/routing/access-policies/index.md): Attach auth requirements to a route or group so denied users never see a flash of protected UI.
- [Route Metadata](https://askrjs.com/docs/routing/route-metadata/index.md): Set titles, meta tags, and structured data per route, and serialize them into server-rendered documents.
- [Data](https://askrjs.com/docs/data/index.md): Choose resources, queries, mutations, and actions by ownership and consistency needs.
- [Choosing a Primitive](https://askrjs.com/docs/data/choosing-a-primitive/index.md): When to reach for a resource, a query, or a plain loader — and what each one owns.
- [Resources](https://askrjs.com/docs/data/resources/index.md): Bind asynchronous work to the active lifecycle so navigating away cancels it instead of resolving into a dead component.
- [Queries and Consistency](https://askrjs.com/docs/data/queries-and-consistency/index.md): Key queries, share results between components, and control how cached data goes stale.
- [Mutations and Invalidation](https://askrjs.com/docs/data/mutations-and-invalidation/index.md): Write through a mutation, invalidate the queries it affects, and let dependents refetch.
- [Server Queries and Preloading](https://askrjs.com/docs/data/server-queries/index.md): Resolve query data on the server and hand it to the browser so hydration does not refetch what you already have.
- [Page Actions and Forms](https://askrjs.com/docs/data/actions-and-forms/index.md): Page actions are POST handlers that return a redirect or field-level errors, and work with JavaScript disabled.

## Documentation navigation

[Previous](https://askrjs.com/docs/core-concepts/determinism/index.md) | [Next](https://askrjs.com/docs/routing/definitions-and-layouts/index.md)
