# Nuxt and Nitro 2

> Register withBetterSupabase as Nitro 2 server middleware with the Nuxt module or toH3V1, and guard server routes.

Source: https://bettersupabase.com/docs/frameworks/nuxt

Nuxt 3 and 4 serve through Nitro 2, which runs on H3 1. Its events wrap Node's
request and response instead of a Web `Request`, so it has its own bridge:
`toH3V1(entries)` from `better-supabase/h3/v1`. H3 2 apps use
[`better-supabase/h3`](/docs/frameworks/h3).

## The Nuxt module [#the-nuxt-module]

Write the entries once in a server module:

```ts title="server/better-supabase.ts"
import { createServer, withBetterSupabase } from "better-supabase/server";
import { betterSupabase } from "../lib/supabase";

export const bs = createServer(betterSupabase);
export default [
  withBetterSupabase(bs, { refresh: true, allow: ["user", "anon"] }),
];
```

Then add the module and point it at that file:

```ts title="nuxt.config.ts"
export default defineNuxtConfig({
  modules: ["better-supabase/nuxt"],
  betterSupabase: { server: "~~/server/better-supabase" },
});
```

The module registers the entries as server middleware, so every server route
reads `db`, `bs`, `auth` and `tenant` from `event.context`, and auto-imports
the Vue composables in components. Set `composables: false` to skip them.

## Without the module [#without-the-module]

Register the middleware yourself in Nitro 2:

```ts title="server/middleware/supabase.ts"
import { toH3V1 } from "better-supabase/h3/v1";
import entries from "../better-supabase";

export default defineEventHandler(toH3V1(entries));
```

## Guards and errors [#guards-and-errors]

`guard(options)` returns the refusal for a caller the options refuse (Problem
Details, or a redirect to `signIn` or `mfa`), or `undefined`:

```ts title="server/api/members.get.ts"
import { guard } from "better-supabase/h3/v1";

const admins = guard({ roles: ["admin"] });

export default defineEventHandler(
  async (event) =>
    (await admins(event)) ?? event.context.db.members.findMany().orThrow(),
);
```

`problemOnError()` turns an error thrown by `.orThrow()` into a Problem Details
`Response` and returns `undefined` for every other error. On Nitro's
Cloudflare presets, `event.context.cloudflare.env` seeds `getEnv`.

The middleware runs before the route handler, so entries that read the final
response (`withDbStats`, `withServerTiming`) see an empty one under H3 1.