> [Agent navigation index](/llms.txt)

# Server middleware and observability

Add application middleware and state, expose safe errors, and emit bounded request telemetry while Brix preserves infrastructure ordering.

## Add middleware and app state

Global business middleware belongs in `defineBrixServer`; route-specific concerns belong on the route. Brix preserves infrastructure ordering around it.

Extend default serialized app state rather than replacing it. Here,
`businessContextMiddleware` is an application-owned Hono middleware:

```ts
export const brixServer = defineBrixServer(brix, {
  middleware: [businessContextMiddleware],
  appState: (c, defaults) => ({
    ...defaults,
    userId: c.req.header("x-user-id"),
  }),
});

```

Defaults include origin, path, initial query, resolved locale, CSP nonce, production flag, and serialization version. Any custom state sent to islands is browser-visible; never include credentials or private server data.

## Handle errors without leaking details

Default 404 and 500 responses are generic JSON. Customize them only when the application needs another public contract. The following examples use an application-owned `telemetry` adapter:

```ts
export const brixServer = defineBrixServer(brix, {
  notFound: (c) => c.json({ error: "Not found" }, 404),
  onError: (error, c) => {
    telemetry.capture(error, c.get("brixRequestId"));
    return c.json({ error: "Request failed" }, 500);
  },
});

```

Unexpected API handler and response-validation failures reach this policy with their original cause. Do not serialize stack traces, provider responses, environment values, or arbitrary error messages. Deliberate Hono `HTTPException` responses pass through route handling.

## Observe requests safely

Every request accepts a valid `x-request-id` or gets a generated one, returns it in the response, and exposes `c.get("brixRequestId")`.

```ts
export const brixServer = defineBrixServer(brix, {
  env,
  service: (c) => ({
    name: "booking",
    version: c.env.VERSION,
    environment: c.env.STAGE,
  }),
  observability: {
    eventTimeoutMs: 1_000,
    onEvent: (event) => telemetry.emit(event),
  },
});

```

Events cover request start, end, and error with method, pathname, request ID, timing, status, incoming `traceparent`, and service metadata. They omit query strings, bodies, and arbitrary headers. Redact dynamic paths and error details before export. Adapter failures are logged and do not fail requests; delivery waits at most one second by default.
