> ## Documentation Index
> Fetch the complete documentation index at: https://better-router.bansal.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Middleware

> Use Hono middleware globally from src/middleware or per-route from _middleware.ts and defineHandler.

better-router uses Hono middleware. A middleware is `(c, next) => void | Promise<void>`.

Order on each request:

1. Request ALS context (`getEnv()` needs this)
2. Global files in `src/middleware` (sorted by file name)
3. Nested `_middleware.ts` from the matched route folder
4. Per-route `middleware` export or `defineHandler(...)` extras
5. Loader / action / HTTP handler

## Global middleware

Files in `src/middleware` run on every request, including `/api/*`. Numeric prefixes control order.

```
src/middleware/01.logger.ts
src/middleware/02.cors.ts
```

```ts title="src/middleware/01.logger.ts" theme={null}
import { defineMiddleware } from "better-router";

export default defineMiddleware(async (c, next) => {
  const started = Date.now();
  await next();
  console.log(c.req.method, c.req.path, c.res.status, `${Date.now() - started}ms`);
});
```

Any `hono/*` helper works. Install `hono` in the app and import it:

```ts title="src/middleware/02.cors.ts" theme={null}
import { cors } from "hono/cors";

export default cors({
  origin: ["http://localhost:5173", "https://app.example.com"],
  credentials: true,
});
```

You usually do **not** need CORS for same-origin `<Form>` and `<Link>`. Add it when a separate frontend or mobile app calls `/api`.

## Nested middleware

`src/routes/admin/_middleware.ts` applies to `/admin/*`. Use it to gate a whole tree:

```ts title="src/routes/app/_middleware.ts" theme={null}
import { defineMiddleware } from "better-router";
import { HTTPException } from "hono/http-exception";
import { getCookie } from "hono/cookie";

export default defineMiddleware(async (c, next) => {
  if (!getCookie(c, "session")) throw new HTTPException(401);
  await next();
});
```

That throws `401` for unsigned-in users. For HTML dashboards, a layout loader that `redirect("/login")` is usually the better UX — see [Errors](/errors).

## Per-route middleware

Pass Hono middleware to `defineHandler` before the handler:

```ts theme={null}
import { defineHandler } from "better-router";
import { basicAuth } from "hono/basic-auth";

export const GET = defineHandler(
  basicAuth({ username: "admin", password: "secret" }),
  (c) => ({ ok: true }),
);
```

Pages can export `middleware` from `.server.tsx`:

```ts theme={null}
import { defineMiddleware } from "better-router";

export const middleware = defineMiddleware(async (c, next) => {
  c.set("requestId", crypto.randomUUID());
  await next();
});
```

## Context variables

```ts title="src/middleware/00.request-id.ts" theme={null}
import { defineMiddleware } from "better-router";

declare module "better-router" {
  interface AppVariables {
    requestId: string;
  }
}

export default defineMiddleware(async (c, next) => {
  c.set("requestId", crypto.randomUUID());
  await next();
});
```

Handlers then call `c.get("requestId")` with the right type.
