@supabase/server - v0.2.0
    Preparing search index...

    Getting Started

    # Deno (import directly)
    import { withSupabase } from 'npm:@supabase/server'

    # npm
    npm install @supabase/server

    # pnpm
    pnpm add @supabase/server

    @supabase/server requires @supabase/supabase-js as a peer dependency:

    # npm
    npm install @supabase/supabase-js

    # pnpm
    pnpm add @supabase/supabase-js

    The fastest way to get a working authenticated endpoint:

    import { withSupabase } from '@supabase/server'

    export default {
    fetch: withSupabase({ allow: 'user' }, async (_req, ctx) => {
    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
    }),
    }

    The export default { fetch } pattern is the standard module worker interface supported by Deno (including Supabase Edge Functions), Bun, and Cloudflare Workers. For Node.js, use the Hono adapter or core primitives with your framework of choice.

    This single wrapper does four things for every request:

    1. CORS — handles OPTIONS preflight and adds CORS headers to all responses
    2. Auth — extracts and verifies credentials from request headers
    3. Clients — creates two Supabase clients: one scoped to the caller, one admin
    4. Errors — returns a JSON error response ({ message, code }) if auth fails

    Your handler only runs when auth succeeds.

    import { withSupabase } from '@supabase/server'

    export default {
    fetch: withSupabase({ allow: 'always' }, async (_req, _ctx) => {
    return Response.json({ status: 'ok', time: new Date().toISOString() })
    }),
    }

    Supabase Edge Functions: By default, the platform requires a valid JWT on every request. If your function uses allow: 'public', allow: 'secret', or allow: 'always', disable the platform-level JWT check in supabase/config.toml:

    [functions.my-function]
    verify_jwt = false
    

    Every handler receives a SupabaseContext with these fields:

    Field Type Description
    supabase SupabaseClient Client scoped to the caller. RLS policies apply.
    supabaseAdmin SupabaseClient Admin client. Bypasses RLS.
    userClaims UserClaims | null JWT-derived identity (id, email, role, appMetadata, userMetadata). null for non-user auth.
    claims JWTClaims | null Raw JWT payload (snake_case). null for non-user auth.
    authType Allow Which auth mode matched: 'user', 'public', 'secret', or 'always'.
    authKeyName string | null Which auth key name of the API key that was used.

    The supabase client respects Row-Level Security. When authType is 'user', the client is scoped to that user's permissions. For other auth modes, it's initialized as anonymous.

    The supabaseAdmin client always bypasses RLS. Use it for operations that need full database access regardless of who's calling.

    userClaims gives you a lightweight view of the user's identity from the JWT. For the full Supabase User object (email confirmation, providers, etc.), call ctx.supabase.auth.getUser().

    When you need the context without the full wrapper — inside a framework route handler, custom middleware, or any situation where you want to control the response yourself:

    import { createSupabaseContext } from '@supabase/server'

    export default {
    fetch: async (req: Request) => {
    const { data: ctx, error } = await createSupabaseContext(req, {
    allow: '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)
    },
    }

    createSupabaseContext returns a result tuple { data, error } instead of producing a Response. This gives you full control over error formatting and response headers.

    CORS is enabled by default with standard supabase-js headers. You can customize or disable it:

    // Custom CORS headers
    withSupabase(
    {
    allow: 'user',
    cors: {
    'Access-Control-Allow-Origin': 'https://myapp.com',
    'Access-Control-Allow-Headers': 'authorization, content-type',
    },
    },
    handler,
    )

    // Disable CORS (e.g., when a framework handles it)
    withSupabase({ allow: 'user', cors: false }, handler)

    withSupabase and createSupabaseContext work with any runtime that supports the Web API Request/Response standard. The core primitives go further — they work in any environment where you can extract headers, regardless of the request/response model (Express, Fastify, etc.).

    • Supabase Edge Functions — environment variables are automatically injected by the platform. Zero config needed.
    • Deno / Bun — works out of the box with the module worker pattern.
    • Node.js — set variables via .env files or your hosting platform. Use the Hono adapter or core primitives to integrate with any framework.
    • Cloudflare Workers — enable nodejs_compat or pass env overrides via the env config option.

    For full details on environment setup per runtime, see environment-variables.md.