### Install Dependencies and Start Development Server Source: https://github.com/supabase/server/blob/main/README.md Use these commands to install project dependencies and start the local development server. ```bash pnpm install pnpm dev ``` -------------------------------- ### Install Supabase Server for Deno and npm Source: https://github.com/supabase/server/blob/main/docs/getting-started.md Install the `@supabase/server` package for Deno or npm. For npm, also install `@supabase/supabase-js` as a peer dependency. ```bash # Deno (import directly) import { withSupabase } from 'npm:@supabase/server' # npm npm install @supabase/server # pnpm pnpm add @supabase/server ``` ```bash # npm npm install @supabase/supabase-js # pnpm pnpm add @supabase/supabase-js ``` -------------------------------- ### Install Dependencies Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Install project dependencies using pnpm. Ensure you have Node.js 20.x or higher and pnpm installed. ```bash pnpm install ``` -------------------------------- ### Minimal .env Example Source: https://github.com/supabase/server/blob/main/docs/environment-variables.md A basic .env file configuration for non-Supabase environments, including essential Supabase variables. ```env SUPABASE_URL=https://.supabase.co SUPABASE_SECRET_KEY=sb_secret_... SUPABASE_PUBLISHABLE_KEY=sb_publishable_... SUPABASE_JWKS={"keys":[...]} ``` -------------------------------- ### Build Project Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Build the project to verify the development setup. This command compiles the library for distribution. ```bash pnpm build ``` -------------------------------- ### Install Elysia Peer Dependency Source: https://github.com/supabase/server/blob/main/docs/adapters/elysia.md Install Elysia as a peer dependency before using the adapter. ```bash pnpm add elysia ``` -------------------------------- ### Install Hono Peer Dependency Source: https://github.com/supabase/server/blob/main/docs/adapters/hono.md Before using the Hono adapter, install Hono as a peer dependency. ```bash pnpm add hono ``` -------------------------------- ### Install H3 Peer Dependency Source: https://github.com/supabase/server/blob/main/docs/adapters/h3.md Install H3 as a peer dependency before using the adapter. ```bash pnpm add h3 ``` -------------------------------- ### Install Supabase Server Package Source: https://github.com/supabase/server/blob/main/README.md Import directly for Deno Edge Functions. Use npm or pnpm for other Node.js environments. ```typescript import { withSupabase } from "npm:@supabase/server"; ``` ```bash npm install @supabase/server ``` ```bash pnpm add @supabase/server ``` -------------------------------- ### Timing-Safe Credential Comparison Example Source: https://github.com/supabase/server/blob/main/docs/security.md Illustrates how to configure endpoints to accept any secret key or a specific named secret key for enhanced security and least privilege. ```typescript withSupabase({ auth: 'secret' }, handler) withSupabase({ auth: 'secret:automations' }, handler) ``` -------------------------------- ### Install NestJS Peer Dependency Source: https://github.com/supabase/server/blob/main/docs/adapters/nestjs.md Install the necessary NestJS packages as peer dependencies before using the adapter. ```bash pnpm add @nestjs/common @nestjs/core ``` -------------------------------- ### Nuxt: File-Based Route with Auth Source: https://github.com/supabase/server/blob/main/docs/adapters/h3.md Example of defining a Nuxt server route with Supabase authentication applied using `defineHandler` and its `middleware` option. ```typescript // server/api/games.get.ts import { defineHandler } from 'h3' import { withSupabase } from '@supabase/server/adapters/h3' export default defineHandler({ middleware: [withSupabase({ auth: 'user' })], handler: async (event) => { const { supabase } = event.context.supabaseContext return supabase.from('favorite_games').select() }, }) ``` -------------------------------- ### Custom Multi-Route Handler Example Source: https://github.com/supabase/server/blob/main/README.md Builds a custom server handler using primitives to manage different routes with distinct authentication requirements and Supabase client scopes. ```typescript import { verifyAuth, createContextClient } from '@supabase/server/core' export default { fetch: async (req) => { const url = new URL(req.url) // Public — no auth needed if (url.pathname === '/health') { return Response.json({ status: 'ok' }) } // Protected — verify the JWT, then create a user-scoped client if (url.pathname === '/games') { const { data: result, error } = await verifyAuth(req, { auth: 'user' }) if (error) return Response.json( { message: error.message }, { status: error.status }, ) const userScopedClient = createContextClient(result.token) const { data: myGames } = await userScopedClient .from('favorite_games') .select() return Response.json(myGames) } return new Response('Not found', { status: 404 }) }, } ``` -------------------------------- ### Custom Multi-Route Handler with Supabase Primitives Source: https://github.com/supabase/server/blob/main/docs/core-primitives.md This example shows how to create a single fetch handler that routes requests based on the URL path. It demonstrates handling public, user-authenticated, and admin-authenticated routes, each with its own verification and client creation logic. ```typescript import { verifyAuth, createContextClient, createAdminClient, } from '@supabase/server/core' export default { fetch: async (req: Request) => { const url = new URL(req.url) // Public route — no auth needed if (url.pathname === '/health') { return Response.json({ status: 'ok' }) } // User-authenticated route if (url.pathname === '/todos') { const { data: auth, error } = await verifyAuth(req, { auth: 'user' }) if (error) { return Response.json( { message: error.message }, { status: error.status }, ) } const supabase = createContextClient({ auth: { token: auth!.token, keyName: auth!.keyName }, }) const { data } = await supabase.from('todos').select() return Response.json(data) } // Admin route — secret key only if (url.pathname === '/admin/users') { const { data: auth, error } = await verifyAuth(req, { auth: 'secret', }) if (error) { return Response.json( { message: error.message }, { status: error.status }, ) } const supabaseAdmin = createAdminClient({ auth: { keyName: auth!.keyName }, }) const { data } = await supabaseAdmin.from('profiles').select() return Response.json(data) } return new Response('Not found', { status: 404 }) }, } ``` -------------------------------- ### Conventional Commit Examples Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Examples of commit messages following the Conventional Commits specification for different types of changes. ```text feat: add support for view operations fix: handle empty namespace list correctly docs: update README with new examples test: add integration tests for table updates feat!: change auth config structure BREAKING CHANGE: auth configuration now uses a discriminated union ``` -------------------------------- ### Add Supabase Server AI Coding Skill Source: https://github.com/supabase/server/blob/main/README.md Install the AI coding skill for agents like Claude Code or Cursor to enable package usage. ```bash npx skills add supabase/server ``` -------------------------------- ### Create Feature Branch Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Create a new branch for your feature development, starting from the 'main' branch. ```bash git checkout -b feat/my-feature ``` -------------------------------- ### Resolve Framework Environment Variables for Supabase Source: https://github.com/supabase/server/blob/main/docs/ssr-frameworks.md Maps framework-specific environment variables to the `Partial` format expected by Supabase core primitives. This example shows mapping Next.js environment variables. ```typescript import type { SupabaseEnv } from '@supabase/server' function resolveEnvFromFramework(): Partial { // Example: Next.js uses NEXT_PUBLIC_* for client-exposed vars const url = process.env.NEXT_PUBLIC_SUPABASE_URL const publishableKey = process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY const secretKey = process.env.SUPABASE_SECRET_KEY return { url: url ?? undefined, publishableKeys: publishableKey ? { default: publishableKey } : {}, secretKeys: secretKey ? { default: secretKey } : {}, // JWKS: either set SUPABASE_JWKS env var, or fetch it (see below) } } ``` -------------------------------- ### Supabase-js Peer Dependency Types Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Example of importing specific types from the `supabase-js` peer dependency. ```typescript import type { SupabaseClient, PostgrestError, AuthError as SupabaseAuthError, // Avoid clashing with this SDK's own `AuthError` class. // ... } from '@supabase/server/peer/supabase-js' ``` -------------------------------- ### Elysia Framework Integration with Supabase Source: https://github.com/supabase/server/blob/main/README.md Integrate Supabase authentication into an Elysia application using the withSupabase adapter. This example protects the '/games' route. ```typescript import { Elysia } from 'elysia' import { withSupabase } from '@supabase/server/adapters/elysia' const app = new Elysia() // Protected — plugin resolves supabaseContext before handlers run .use(withSupabase({ auth: 'user' })) .get('/games', async ({ supabaseContext }) => { const { data: myGames } = await supabaseContext.supabase .from('favorite_games') .select() return myGames }) // Public — no plugin means no auth .get('/health', () => ({ status: 'ok' })) app.listen(3000) ``` -------------------------------- ### Named Key Validation in Supabase Client Source: https://github.com/supabase/server/blob/main/docs/environment-variables.md Example of how to specify named keys for authentication within the Supabase client configuration. ```typescript // Only accept the "web" publishable key withSupabase({ auth: 'publishable:web' }, handler) // Accept any secret key withSupabase({ auth: 'secret:*' }, handler) ``` -------------------------------- ### Resolve environment variables with resolveEnv Source: https://github.com/supabase/server/blob/main/docs/environment-variables.md Manually resolve Supabase environment variables using `resolveEnv` for testing or custom setups. Handles potential errors if required variables are missing. ```typescript import { resolveEnv } from '@supabase/server/core' const { data: env, error } = resolveEnv() if (error) { console.error(`Missing config: ${error.message}`) } ``` -------------------------------- ### Supabase Client Options Source: https://github.com/supabase/server/blob/main/docs/adapters/nestjs.md Forward options to the underlying `createClient()` calls using `supabaseOptions`. ```typescript import { UseGuards } from '@nestjs/common'; import { withSupabase } from '@supabase/nestjs-shared'; @UseGuards( withSupabase({ auth: 'user', supabaseOptions: { db: { schema: 'api' } }, }), ) class MyGuard {} ``` -------------------------------- ### Format Code Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Format all project code using Prettier. This ensures consistent code style across the project. ```bash pnpm format ``` -------------------------------- ### Clone Repository Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Clone the server repository from GitHub. Replace YOUR_USERNAME with your GitHub username. ```bash git clone https://github.com/YOUR_USERNAME/server.git cd server ``` -------------------------------- ### Basic withSupabase Configuration Source: https://github.com/supabase/server/blob/main/README.md Configure withSupabase with authentication, CORS disabled, and environment overrides. The handler function will be executed with the Supabase context. ```typescript withSupabase( { auth: 'user', // who can call this function cors: false, // disable CORS (default: supabase-js CORS headers) env: { url: '...' }, // env overrides (optional) }, handler, ) ``` -------------------------------- ### Elysia Scoped Route Protection with Supabase Source: https://github.com/supabase/server/blob/main/README.md Implement per-route authentication in Elysia using scoped groups and the withSupabase adapter. This example protects the '/api' group. ```typescript import { Elysia } from 'elysia' import { withSupabase } from '@supabase/server/adapters/elysia' const app = new Elysia() .get('/health', () => ({ status: 'ok' })) .group('/api', (app) => app .use(withSupabase({ auth: 'user' })) .get('/profile', async ({ supabaseContext }) => { return supabaseContext.userClaims }), ) app.listen(3000) ``` -------------------------------- ### Forward Supabase Client Options in Elysia Adapter Source: https://github.com/supabase/server/blob/main/docs/adapters/elysia.md Pass options to the underlying `createClient()` calls for the Supabase client by using the `supabaseOptions` property within the `withSupabase` configuration. This allows for customization of the Supabase client, such as setting a specific schema. ```typescript app.use( withSupabase({ auth: 'user', supabaseOptions: { db: { schema: 'api' } }, }), ) ``` -------------------------------- ### H3 Adapter with CORS Handling Source: https://github.com/supabase/server/blob/main/docs/adapters/h3.md Example of integrating Supabase H3 adapter with H3's built-in CORS handling utilities. The adapter itself does not manage CORS. ```typescript import { H3, handleCors } from 'h3' import { withSupabase } from '@supabase/server/adapters/h3' const app = new H3() app.use((event) => handleCors(event, { origin: '*' })) app.use(withSupabase({ auth: 'user' })) app.get('/todos', async (event) => { const { supabase } = event.context.supabaseContext const { data } = await supabase.from('todos').select() return data }) export default { fetch: app.fetch } ``` -------------------------------- ### withSupabase Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Wraps a fetch handler with authentication, CORS, and client creation. It returns a function suitable for `export default { fetch }`. ```APIDOC ## withSupabase ### Description Wraps a fetch handler with auth, CORS, and client creation. Returns a `(req: Request) => Promise` function suitable for `export default { fetch }`. - Handles `OPTIONS` preflight when CORS is enabled - Verifies credentials per `config.auth` - Returns JSON error response on auth failure - Adds CORS headers to all responses ### Signature ```ts function withSupabase( config: WithSupabaseConfig, handler: (req: Request, ctx: SupabaseContext) => Promise ): (req: Request) => Promise ``` ``` -------------------------------- ### Development Build Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Run the build process in watch mode for development. This command rebuilds the project automatically on file changes. ```bash pnpm run dev ``` -------------------------------- ### Hono Adapter with `withSupabase` (Deno / Edge Functions) Source: https://github.com/supabase/server/blob/main/skills/supabase-server/SKILL.md Hono middleware for Supabase integration in Deno environments. Requires `npm:@supabase/server/adapters/hono`. CORS is not handled by the adapter and must be configured separately. ```typescript import { Hono } from 'npm:hono' import { withSupabase } from 'npm:@supabase/server/adapters/hono' const app = new Hono() app.use('*', withSupabase({ auth: 'user' })) app.get('/todos', async (c) => { const { supabase } = c.var.supabaseContext const { data } = await supabase.from('todos').select() return c.json(data) }) export default { fetch: app.fetch } ``` -------------------------------- ### Forward Supabase Client Options in Hono Adapter Source: https://github.com/supabase/server/blob/main/docs/adapters/hono.md Use `supabaseOptions` to pass configuration directly to the underlying `createClient()` calls within the Hono adapter. ```typescript app.use( '*', withSupabase({ auth: 'user', supabaseOptions: { db: { schema: 'api' } }, }), ) ``` -------------------------------- ### Singular vs Plural Key Equivalence Source: https://github.com/supabase/server/blob/main/docs/environment-variables.md Demonstrates that setting a singular key is equivalent to setting the plural form with a single 'default' entry. ```env # These two are the same: SUPABASE_PUBLISHABLE_KEY=sb_publishable_default_abc SUPABASE_PUBLISHABLE_KEYS={"default":"sb_publishable_default_abc"} ``` -------------------------------- ### Integrating CORS with Elysia and Supabase Source: https://github.com/supabase/server/blob/main/docs/adapters/elysia.md Handle CORS separately using Elysia's CORS plugin, as the Supabase adapter does not manage CORS. This example shows how to apply CORS before the Supabase authentication plugin. ```typescript import { Elysia } from 'elysia' import { cors } from '@elysiajs/cors' import { withSupabase } from '@supabase/server/adapters/elysia' const app = new Elysia() .use(cors()) .use(withSupabase({ auth: 'user' })) .get('/todos', async ({ supabaseContext }) => { const { data } = await supabaseContext.supabase.from('todos').select() return data }) app.listen(3000) ``` -------------------------------- ### Supabase Usage in Next.js Server Component Source: https://github.com/supabase/server/blob/main/docs/ssr-frameworks.md Demonstrates how to create a Supabase context and fetch data within a Next.js Server Component. Redirects to login if authentication fails. ```tsx // app/page.tsx import { createSupabaseContext } from '@/lib/supabase/context' import { redirect } from 'next/navigation' export default async function Home() { const { data: ctx, error } = await createSupabaseContext() if (error) { redirect('/auth/login') } const { data: todos } = await ctx!.supabase.from('todos').select() return (
    {todos?.map((t) => (
  • {t.title}
  • ))}
) } ``` -------------------------------- ### Supabase Edge Functions with `withSupabase` (Deno) Source: https://github.com/supabase/server/blob/main/skills/supabase-server/SKILL.md High-level wrapper for Supabase Edge Functions in Deno. Requires `npm:@supabase/server`. Assumes `auth: 'user'` and automatically injects environment variables. ```typescript import { withSupabase } from 'npm:@supabase/server' export default { fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { const { data } = await ctx.supabase.from('todos').select() return Response.json(data) }), } ``` -------------------------------- ### Basic Elysia App with Supabase Auth Source: https://github.com/supabase/server/blob/main/docs/adapters/elysia.md Set up a basic Elysia application with Supabase authentication for user routes. The `supabaseContext` is available in route handlers. ```typescript import { Elysia } from 'elysia' import { withSupabase } from '@supabase/server/adapters/elysia' const app = new Elysia() .use(withSupabase({ auth: 'user' })) .get('/todos', async ({ supabaseContext }) => { const { data } = await supabaseContext.supabase.from('todos').select() return data }) app.listen(3000) ``` -------------------------------- ### Push to Fork Source: https://github.com/supabase/server/blob/main/CONTRIBUTING.md Push your feature branch to your forked repository. ```bash git push origin feat/my-feature ``` -------------------------------- ### CreateContextClientOptions Interface Definition Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Options for creating a Supabase client within a context. ```typescript interface CreateContextClientOptions { auth?: ClientAuth env?: Partial supabaseOptions?: SupabaseClientOptions } ``` -------------------------------- ### SupabaseEnv Interface Definition Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Environment variables and settings for Supabase client initialization. ```typescript interface SupabaseEnv { url: string publishableKeys: Record secretKeys: Record jwks: JsonWebKeySet | null } ``` -------------------------------- ### Hono Adapter with `withSupabase` (Node.js / Bun) Source: https://github.com/supabase/server/blob/main/skills/supabase-server/SKILL.md Hono middleware for Supabase integration. Requires `@supabase/server/adapters/hono`. CORS is not handled by the adapter and must be configured separately. ```typescript import { Hono } from 'hono' import { withSupabase } from '@supabase/server/adapters/hono' const app = new Hono() app.use('*', withSupabase({ auth: 'user' })) app.get('/todos', async (c) => { const { supabase } = c.var.supabaseContext const { data } = await supabase.from('todos').select() return c.json(data) }) export default app ``` -------------------------------- ### Create Supabase Clients Source: https://github.com/supabase/server/blob/main/README.md Creates Supabase clients with different scopes: user-scoped with RLS, anonymous with RLS, or an admin client that bypasses RLS. ```typescript const userScopedClient = createContextClient(auth.token) // RLS applies as this user const anonClient = createContextClient() // RLS applies as anon role const adminClient = createAdminClient() // bypasses RLS entirely ``` -------------------------------- ### Create User-Scoped Supabase Client Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Use `createContextClient` to instantiate a Supabase client with Row Level Security (RLS) enabled. It requires publishable key and user JWT, and will throw an `EnvError` if essential configuration is missing. ```typescript function createContextClient( options?: CreateContextClientOptions, ): SupabaseClient ``` -------------------------------- ### Create Admin Supabase Client Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Use `createAdminClient` to create an admin Supabase client that bypasses RLS. This function requires the Supabase URL and secret key, and will throw an `EnvError` if they are not provided. ```typescript function createAdminClient( options?: CreateAdminClientOptions, ): SupabaseClient ``` -------------------------------- ### Multiple Auth Modes with Array Syntax Source: https://github.com/supabase/server/blob/main/docs/auth-modes.md Configure Supabase to accept multiple authentication methods in a specified order. The first matching mode is used. `ctx.authMode` indicates which mode was successful. ```typescript import { withSupabase } from '@supabase/server' export default { fetch: withSupabase({ auth: ['user', 'secret'] }, async (req, ctx) => { // ctx.authMode tells you which mode matched if (ctx.authMode === 'user') { // Called by an authenticated user const { data } = await ctx.supabase.from('reports').select() return Response.json(data) } // Called by another service with a secret key const { user_id } = await req.json() const { data } = await ctx.supabaseAdmin .from('reports') .select() .eq('user_id', user_id) return Response.json(data) }), } ``` -------------------------------- ### Supabase Edge Functions with `createSupabaseContext` (Deno) Source: https://github.com/supabase/server/blob/main/skills/supabase-server/SKILL.md Provides custom response control for Supabase Edge Functions in Deno. Requires `npm:@supabase/server`. Automatically injects environment variables and handles authentication. ```typescript import { createSupabaseContext } from 'npm:@supabase/server' export default { fetch: async (req: Request) => { const { data: ctx, error } = await createSupabaseContext(req, { auth: 'user', }) if (error) { return Response.json( { message: error.message, code: error.code }, { status: error.status }, ) } const { data } = await ctx.supabase.from('todos').select() return Response.json(data) }, } ``` -------------------------------- ### Basic Controller with Supabase Auth Guard Source: https://github.com/supabase/server/blob/main/docs/adapters/nestjs.md Demonstrates a basic NestJS controller using the `withSupabase` guard for authentication and `@SupabaseCtx` to access Supabase context within handlers. ```typescript // games.controller.ts import { Controller, Get, UseGuards } from '@nestjs/common' import { withSupabase, SupabaseCtx } from '@supabase/server/adapters/nestjs' import type { SupabaseContext } from '@supabase/server' @Controller('games') @UseGuards(withSupabase({ auth: 'user' })) export class GamesController { @Get() async list(@SupabaseCtx() ctx: SupabaseContext) { const { data } = await ctx.supabase.from('favorite_games').select() return data } @Get('me') me(@SupabaseCtx('userClaims') user: SupabaseContext['userClaims']) { return user } } ``` -------------------------------- ### Named Keys Configuration Source: https://github.com/supabase/server/blob/main/docs/environment-variables.md Configuration for multiple keys using plural environment variables, suitable for different clients like web and mobile. ```env SUPABASE_PUBLISHABLE_KEYS={"default":"sb_publishable_default_abc","web":"sb_publishable_web_xyz","mobile":"sb_publishable_mobile_123"} SUPABASE_SECRET_KEYS={"default":"sb_secret_default_abc","internal":"sb_secret_internal_xyz"} ``` -------------------------------- ### Initialize Supabase Client with User Authentication Source: https://github.com/supabase/server/blob/main/README.md This snippet demonstrates how to initialize the Supabase client with user authentication enabled. The handler will only execute if the user is authenticated, and Row Level Security (RLS) will automatically scope data access to the authenticated user. ```typescript import { withSupabase } from '@supabase/server' export default { fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { // RLS-scoped — this user only sees their own favorites const { data: myGames } = await ctx.supabase.from('favorite_games').select() return Response.json(myGames) }), } ``` -------------------------------- ### CreateAdminClientOptions Interface Definition Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Options for creating a Supabase admin client. ```typescript interface CreateAdminClientOptions { auth?: Pick env?: Partial supabaseOptions?: SupabaseClientOptions } ``` -------------------------------- ### createAdminClient Source: https://github.com/supabase/server/blob/main/docs/core-primitives.md Creates a Supabase client that bypasses Row-Level Security (RLS) using a secret key. ```APIDOC ## createAdminClient ### Description Creates a Supabase client that bypasses Row-Level Security using a secret key. ### Usage ```typescript import { createAdminClient } from '@supabase/server/core' const supabaseAdmin = createAdminClient() ``` ### Usage with Named Key ```typescript // With a specific named key const supabaseAdminInternal = createAdminClient({ auth: { keyName: 'internal' }, }) ``` ### Configuration Same server-safe settings as `createContextClient`. ### Error Handling Throws `EnvError` if the secret key is missing. ``` -------------------------------- ### Create Supabase Context Source: https://github.com/supabase/server/blob/main/README.md Assembles the full Supabase context from a Request, combining authentication verification and client creation into a single call. ```typescript const { data: ctx, error } = await createSupabaseContext(req, { auth: 'user' }) ``` -------------------------------- ### createContextClient Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Creates a user-scoped Supabase client where Row Level Security (RLS) is applied. This function throws an `EnvError` if the URL or publishable key is missing. ```APIDOC ## createContextClient ### Description Creates a user-scoped Supabase client. RLS applies. **Throws `EnvError`** if URL or publishable key is missing. Configured with: - Publishable key (named or default) as `apikey` header - User's JWT as `Authorization: Bearer` header (when `auth.token` is provided) - `persistSession: false`, `autoRefreshToken: false`, `detectSessionInUrl: false` ### Signature ```ts function createContextClient( options?: CreateContextClientOptions ): SupabaseClient ``` ``` -------------------------------- ### Import Core Primitives Source: https://github.com/supabase/server/blob/main/README.md Imports necessary functions from the `@supabase/server/core` package for advanced Supabase operations. ```typescript import { verifyAuth, createContextClient, createAdminClient, } from '@supabase/server/core' ``` -------------------------------- ### Wrap Fetch Handler with Supabase Auth and Client Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Use `withSupabase` to wrap a fetch handler, enabling authentication, CORS, and Supabase client creation. It handles OPTIONS requests, verifies credentials, and adds CORS headers. ```typescript function withSupabase( config: WithSupabaseConfig, handler: (req: Request, ctx: SupabaseContext) => Promise, ): (req: Request) => Promise ``` -------------------------------- ### withSupabase (Hono) Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Hono middleware that sets `c.var.supabaseContext` on the Hono context. It handles authentication failures by throwing an `HTTPException` with `cause: AuthError`. The middleware skips execution if `c.var.supabaseContext` is already set, allowing for route-level overrides. Defaults to `auth: 'user'` if no configuration is provided. ```APIDOC ## withSupabase (Hono) ### Description Hono middleware that sets `c.var.supabaseContext` on the Hono context. It handles authentication failures by throwing an `HTTPException` with `cause: AuthError`. The middleware skips execution if `c.var.supabaseContext` is already set, allowing for route-level overrides. Defaults to `auth: 'user'` if no configuration is provided. ### Method ```ts function withSupabase(config?: Omit): MiddlewareHandler ``` ### Parameters #### Request Body - **config** (Omit) - Optional - Configuration object for the middleware. If omitted, defaults to `auth: 'user'`. ### SupabaseContext Sets `c.var.supabaseContext` which is of type `SupabaseContext`. ### Error Handling Throws `HTTPException` on auth failure with `cause: AuthError`. ``` -------------------------------- ### Create an Authenticated Endpoint with Supabase Server Source: https://github.com/supabase/server/blob/main/docs/getting-started.md Use the `withSupabase` wrapper to create an authenticated endpoint. This wrapper handles CORS, authentication, Supabase client creation, and error responses. Your handler only runs if authentication succeeds. ```typescript import { withSupabase } from '@supabase/server' export default { fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { const { data } = await ctx.supabase.from('todos').select() return Response.json(data) }), } ``` -------------------------------- ### createSupabaseContext Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Creates a `SupabaseContext` from a request. It returns a result tuple containing either the context data or an authentication error. ```APIDOC ## createSupabaseContext ### Description Creates a `SupabaseContext` from a request. Returns a result tuple. The `cors` option is ignored. Defaults to `auth: 'user'` when `options` is omitted. ### Signature ```ts function createSupabaseContext( request: Request, options?: WithSupabaseConfig ): Promise< | { data: SupabaseContext; error: null } | { data: null; error: AuthError } > ``` ``` -------------------------------- ### createContextClient Source: https://github.com/supabase/server/blob/main/docs/core-primitives.md Creates a Supabase client scoped to the caller's identity, applying RLS policies. Can be used with user tokens or anonymously. ```APIDOC ## createContextClient ### Description Creates a Supabase client scoped to the caller's identity. RLS policies apply. ### Usage with User Token ```typescript import { verifyAuth, createContextClient } from '@supabase/server/core' // With a user's token (from verifyAuth) const { data: auth } = await verifyAuth(request, { auth: 'user' }) const supabase = createContextClient({ auth: { token: auth!.token, keyName: auth!.keyName }, }) ``` ### Usage Anonymously ```typescript // Anonymous (no token) — RLS as anon role const anonClient = createContextClient() ``` ### Configuration The client is configured with: - The publishable key as the `apikey` header - The user's JWT as the `Authorization: Bearer` header (if token is provided) - Server-safe auth settings: `persistSession: false`, `autoRefreshToken: false`, `detectSessionInUrl: false` ### Error Handling This function throws `EnvError` if `SUPABASE_URL` or the required publishable key is missing. Wrap in try/catch when using directly. ``` -------------------------------- ### Handle Client Factory Errors with Try-Catch Source: https://github.com/supabase/server/blob/main/docs/error-handling.md Wrap calls to client factory functions like `createContextClient` and `createAdminClient` in a try-catch block. Catch specific errors like `EnvError` for configuration issues. ```typescript import { verifyAuth, createContextClient, createAdminClient, } from '@supabase/server/core' import { EnvError } from '@supabase/server' const { data: auth, error } = await verifyAuth(request, { auth: 'user' }) // ... handle error ... try { const supabase = createContextClient({ auth: { token: auth!.token } }) const supabaseAdmin = createAdminClient() } catch (e) { if (e instanceof EnvError) { console.error(`Config issue [${e.code}]: ${e.message}`) return Response.json({ message: e.message }, { status: 500 }) } throw e } ``` -------------------------------- ### Create a Public Endpoint with Supabase Server Source: https://github.com/supabase/server/blob/main/docs/getting-started.md Create a public endpoint by setting `auth: 'none'` in the `withSupabase` wrapper. This allows requests without authentication. ```typescript import { withSupabase } from '@supabase/server' export default { fetch: withSupabase({ auth: 'none' }, async (_req, _ctx) => { return Response.json({ status: 'ok', time: new Date().toISOString() }) }), } ``` -------------------------------- ### Using Generics with Hono Adapter Source: https://github.com/supabase/server/blob/main/docs/typescript-generics.md Configure the Hono adapter with `withSupabase` to inject a typed Supabase client into Hono's environment variables. This allows typed access to Supabase within Hono route handlers. ```typescript import { Hono } from 'hono' import { withSupabase } from '@supabase/server/adapters/hono' import type { SupabaseContext } from '@supabase/server' import type { Database } from './database.types.ts' type Env = { Variables: { supabaseContext: SupabaseContext } } const app = new Hono() app.use('*', withSupabase({ auth: 'user' })) app.get('/todos', async (c) => { const { supabase } = c.var.supabaseContext const { data } = await supabase.from('todos').select('id, title') return c.json(data) }) ``` -------------------------------- ### resolveEnv Source: https://github.com/supabase/server/blob/main/docs/core-primitives.md Resolves Supabase environment configuration from runtime variables. Requires `SUPABASE_URL`. Can be overridden with partial options. ```APIDOC ## resolveEnv ### Description Resolves Supabase environment configuration from runtime variables. The only hard requirement is `SUPABASE_URL`. ### Usage ```typescript import { resolveEnv } from '@supabase/server/core' const { data: env, error } = resolveEnv() if (error) { // error is an EnvError — e.g., SUPABASE_URL not set console.error(error.message) } ``` ### Overrides ```typescript const { data: envOverridden } = resolveEnv({ url: 'http://localhost:54321', }) ``` ### Returns `{ data: SupabaseEnv, error: null }` on success, `{ data: null, error: EnvError }` on failure. ``` -------------------------------- ### resolveEnv Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Resolves Supabase environment configuration from runtime variables. `SUPABASE_URL` is the only mandatory variable. ```APIDOC ## resolveEnv ### Description Resolves Supabase environment configuration from runtime variables. `SUPABASE_URL` is the only hard requirement. ### Signature ```ts function resolveEnv( overrides?: Partial ): { data: SupabaseEnv; error: null } | { data: null; error: EnvError } ``` ``` -------------------------------- ### Singular Key Configuration Source: https://github.com/supabase/server/blob/main/docs/environment-variables.md Using singular environment variables for a single default key, which is a convenience for common use cases. ```env SUPABASE_PUBLISHABLE_KEY=sb_publishable_default_abc SUPABASE_SECRET_KEY=sb_secret_default_abc ``` -------------------------------- ### Using Generics with createSupabaseContext Source: https://github.com/supabase/server/blob/main/docs/typescript-generics.md Utilize `createSupabaseContext` to establish typed Supabase clients (`supabase` and `supabaseAdmin`) within your application context. This requires passing the request object and authentication options. ```typescript import { createSupabaseContext } from '@supabase/server' import type { Database } from './database.types.ts' const { data: ctx, error } = await createSupabaseContext(request, { auth: 'user', }) if (error) { throw error } // ctx.supabase and ctx.supabaseAdmin are both SupabaseClient const { data } = await ctx!.supabase.from('profiles').select('id, email') ``` -------------------------------- ### Migrate Legacy Edge Function to @supabase/server Source: https://github.com/supabase/server/blob/main/skills/supabase-server/SKILL.md Modernize legacy Edge Functions by replacing manual Supabase client creation and auth forwarding with the `withSupabase` helper. This simplifies code, improves security, and ensures cross-platform compatibility. ```typescript import { createClient } from 'npm:@supabase/supabase-js@2' Deno.serve(async (req: Request) => { const supabaseClient = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_ANON_KEY') ?? '', { global: { headers: { Authorization: req.headers.get('Authorization')! } }, }, ) const { data } = await supabaseClient.from('orders').select('*') return Response.json(data) }) ``` ```typescript import { withSupabase } from 'npm:@supabase/server' export default { fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { const { data } = await ctx.supabase.from('orders').select('*') return Response.json(data) }), } ``` -------------------------------- ### createAdminClient Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Creates an admin Supabase client that bypasses Row Level Security (RLS). This function throws an `EnvError` if the URL or secret key is missing. ```APIDOC ## createAdminClient ### Description Creates an admin Supabase client that bypasses RLS. **Throws `EnvError`** if URL or secret key is missing. ### Signature ```ts function createAdminClient( options?: CreateAdminClientOptions ): SupabaseClient ``` ``` -------------------------------- ### Nuxt: App-Wide Supabase Auth Middleware Source: https://github.com/supabase/server/blob/main/docs/adapters/h3.md Registering `withSupabase` as a server middleware in Nuxt to apply authentication to all routes. ```typescript // server/middleware/supabase.ts import { withSupabase } from '@supabase/server/adapters/h3' export default withSupabase({ auth: 'user' }) ``` -------------------------------- ### withSupabase (Elysia) Source: https://github.com/supabase/server/blob/main/docs/api-reference.md Elysia plugin that resolves `supabaseContext` into the request context. It throws an error on authentication failure with `cause: AuthError`. The plugin skips execution if `supabaseContext` has already been resolved by a prior plugin. Defaults to `auth: 'user'` when the configuration is omitted. ```APIDOC ## withSupabase (Elysia) ### Description Elysia plugin that resolves `supabaseContext` into the request context. It throws an error on authentication failure with `cause: AuthError`. The plugin skips execution if `supabaseContext` has already been resolved by a prior plugin. Defaults to `auth: 'user'` when the configuration is omitted. ### Method ```ts function withSupabase(config?: Omit): Elysia ``` ### Parameters #### Request Body - **config** (Omit) - Optional - Configuration object for the plugin. If omitted, defaults to `auth: 'user'`. ### SupabaseContext Resolves `supabaseContext` into the request context, which is of type `SupabaseContext`. ### Error Handling Throws an error on auth failure with `cause: AuthError`. ```