Files
supabase/apps/docs/spec/reference/middleware/v1/partials/usage-examples.mdx
T
Katerina Skroumpelou 2013ebf417 docs: drop alpha labels and pin server and middleware imports to a major (#51031)
## Problem

`@supabase/middleware` ships as 1.0.0. The docs still label the
`pipeline` entry form of `withSupabase` alpha, and several snippets
import `npm:@supabase/server` and `npm:@supabase/middleware` with no
version or with a `^0.5.0` pin. A snippet without a version leaves
readers and tools to guess one, and a guessed version fails on deploy.

## Solution

- Removes the alpha wording from the middleware reference intro and
usage examples, the server frameworks partial, and the Bring your own
MCP guide. The `@supabase/server` 1.6.0 floor stays.
- Pins every `npm:@supabase/server` and `npm:@supabase/middleware`
import in the guides to a major range, `@1`, following the
`npm:@supabase/supabase-js@2` convention in Managing dependencies.
- Bumps the authenticated-mcp-server example to middleware `^1.0.0` and
server `^1.9.0`.

~~Blocked by supabase/middleware#49. The `@1` range resolves once 1.0.0
is on npm.~~




<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated authentication, API key, and MCP examples to use versioned
Supabase server and middleware packages.
* Clarified that pipeline and nested composition behave the same, and
that both require `@supabase/server` 1.6.0 or later.
* Removed alpha-status labels from `withSupabase` guidance while
retaining the 1.6.0 minimum-version requirement.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-30 17:27:44 +03:00

89 lines
3.8 KiB
Plaintext

---
id: usage-examples
title: Usage examples
---
Each example builds one Fetch handler with `pipeline`. Entries run in array order on the request. The handler runs last and reads what the entries contributed to `ctx`.
### Gate a route behind CORS and a feature flag
<RefSubLayout.EducationRow>
<RefSubLayout.Details>
`withCors` runs first. It answers the CORS preflight (an `OPTIONS` request carrying `Access-Control-Request-Method`) with `204` before anything else runs. On the way out, it stamps `Access-Control-*` headers onto the response when the request's `Origin` is allowed.
`withFeatureFlag` runs second. `evaluate` receives the request and decides: `true` admits it, `false` rejects it. It can be async, and it can return a verdict object instead of a boolean. A rejected request gets a `404` and never reaches the handler. An admitted request reaches the handler with `ctx.featureFlag` set.
Both middleware ship in `@supabase/middleware`. The handler is plain Fetch, so the same stack runs on Node, Deno, Bun, and Cloudflare Workers; only the host entry point differs.
</RefSubLayout.Details>
<RefSubLayout.Examples>
```ts
import { pipeline } from '@supabase/middleware'
import { withCors } from '@supabase/middleware/cors'
import { withFeatureFlag } from '@supabase/middleware/feature-flag'
export default {
fetch: pipeline(
[
withCors({ origin: ['https://app.example.com'], credentials: true }),
withFeatureFlag({
name: 'beta-checkout',
evaluate: (req) => req.headers.get('x-beta') === '1',
}),
],
async (_req, ctx) => Response.json({ feature: ctx.featureFlag.name }),
),
}
```
</RefSubLayout.Examples>
</RefSubLayout.EducationRow>
### Roll out an authenticated endpoint behind a flag
<RefSubLayout.EducationRow>
<RefSubLayout.Details>
Middleware from [`@supabase/server`](/docs/reference/server/introduction) drop into the same array. `withCors` runs first, so the preflight is answered before the auth gate. `withSupabase` runs second with `cors: 'disabled'`, because `withCors` owns CORS here. It verifies the caller's JWT and puts an RLS-scoped client on `ctx.supabase`. A request without valid credentials gets a `401` and never reaches the flag or the handler.
The flag runs last. `evaluate` reads an environment variable through `getEnv`, so the endpoint returns `404` to every signed-in caller until `BETA_CHECKOUT` is set to `on`. Flip the variable to roll the endpoint out.
Without `withCors`, `withSupabase` answers every `OPTIONS` request itself with `204` and wildcard CORS headers (`Access-Control-Allow-Origin: *`). That is enough when you do not need an origin allowlist. A layer that owns CORS must sit before `withSupabase` in the array. Placed after it, the preflight reaches the auth gate and gets a `401`.
The entry form of `withSupabase` needs `@supabase/server` 1.6.0 or later.
</RefSubLayout.Details>
<RefSubLayout.Examples>
```ts
import { getEnv, pipeline } from '@supabase/middleware'
import { withCors } from '@supabase/middleware/cors'
import { withFeatureFlag } from '@supabase/middleware/feature-flag'
import { withSupabase } from '@supabase/server'
export default {
fetch: pipeline(
[
withCors({ origin: ['https://app.example.com'] }),
withSupabase({ auth: 'user', cors: 'disabled' }),
withFeatureFlag({
name: 'beta-checkout',
evaluate: () => getEnv('BETA_CHECKOUT') === 'on',
}),
],
async (_req, ctx) => {
const { data, error } = await ctx.supabase.from('carts').select()
if (error) return Response.json({ error: 'query_failed' }, { status: 500 })
return Response.json(data)
},
),
}
```
</RefSubLayout.Examples>
</RefSubLayout.EducationRow>