# Routing

Rebask maps files under `app/` to URLs.

## Pages and layouts

layouts nest around pages. Each page and layout is also known as a `"segment"`.

```bash
app/
  layout.tsx          → wraps every page
  page.tsx            → /
  about/page.tsx      → /about
  products/
    layout.tsx        → wraps /products/*
    page.tsx          → /products
    [id]/page.tsx     → /products/:id
```

The final page is a combination of the page segment and its related layout segments. This
distinction is useful to understand how [prefetching](./navigations.md#link) works for navigations,
as the router only fetches missing segments.

## Route handlers

Add a `route.ts` file to handle HTTP methods:

```bash
app/
  api/
    hello/route.ts    → /api/hello
    products/
      [id]/route.ts   → /api/products/:id
```

See [Route handlers](./route-handlers.md) to learn more.

## Dynamic segments

Pages and route handlers can define dynamic segments using brackets:

| Folder        | Param key | Type                    |
| ------------- | --------- | ----------------------- |
| `[id]`        | `id`      | `string`                |
| `[...slug]`   | `slug`    | `string[]`              |
| `[[...slug]]` | `slug`    | `string[] \| undefined` |
| `(group)`     | —         | —                       |

Route groups organize files without changing the URL. This is particularly useful for having multiple layouts at the same path level:

```bash
app/
  (shop)/layout.tsx          → shop nav layout
  (shop)/products/page.tsx   → /products
  (marketing)/layout.tsx     → marketing nav layout
  (marketing)/about/page.tsx → /about
```

Duplicate URL signatures across route groups, pages and route handlers fail at build time.

Use [`routeParams()`](../server-runtime-apis.md#routeparams) to read values from dynamic route segments:

```tsx
// app/products/[id]/page.tsx
import { routeParams } from "@rebask/core/request"

export default async function ProductPage() {
  const { id } = await routeParams<{ id: string }>()
  return <h1>Product {id}</h1>
}
```

## Custom 404 page

If no page matches the URL, a catch-all page marked [`notFound`](../error-handling.md#unmatched-urls)
can be used to render a custom 404.

## `prerenderParams`

Export `prerenderParams` from a dynamic page to list paths to
[prerender at build-time](../caching/page-caching.md):

```ts
// app/products/[id]/page.tsx
export async function prerenderParams() {
  return {
    params: [{ id: "1" }, { id: "2" }],
    allowExtraParams: false,
  }
}
```

| Field              | Type                                   | Default | Description                                                                                                                    |
| ------------------ | -------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `params`           | `Record<string, string \| string[]>[]` | —       | Params to prerender (e.g. `{ id: "1" }` → `/products/1`). Keys match dynamic segment names.                                    |
| `allowExtraParams` | `boolean?`                             | `true`  | `true` accepts parameter values not listed in `params`. `false` only allows listed paths and returns a 404 for unlisted paths. |

## Reserved routes

Rebask uses `/_rebask/` for internal requests. Do not create app routes under that prefix.
