* docs: add initial documentation and skills.md
* docs: apply formatting
* docs: update SKILL.md to resolve docs from package location and ship docs with npm
SKILL.md now instructs agents to find documentation in the installed
@supabase/server package (node_modules or repo root) instead of using
relative paths. Added docs/ and SKILL.md to package.json files array
so they ship with npm installs.
* docs: add missing HTTPException import in error-handling example
* docs: fix strictNullChecks issues, duplicate variables, and missing context in examples
- Add non-null assertions (!) after error guards where TS can't narrow
destructured result tuples
- Split duplicate variable declarations into separate code blocks
- Add missing imports and show where variables like `auth` come from
- Keep { data, error } destructuring pattern consistent with SDK convention
* docs: reframe as runtime-agnostic and add env auto-injection details
- getting-started: replace Edge Function framing with runtime-neutral
language, explain module worker pattern works across Deno/Bun/Workers,
add Runtimes section covering all supported environments
- webhooks: replace Deno.env with process.env for portable examples
- environment-variables: add "Auto-injected in" column distinguishing
Platform vs Local CLI, reframe section headers
- auth-modes: clean up example key values
- core-primitives: clarify "Integration with frameworks" wording
- types: simplify TSDoc for publishable/secret key descriptions
* docs: add SSR frameworks guide and update references
Add docs/ssr-frameworks.md covering the pattern for using core
primitives in Next.js, SvelteKit, Nuxt, and Remix — cookie extraction,
env bridging, JWKS caching, and a complete Next.js adapter example.
Replace the basic SSR example in core-primitives.md with a pointer
to the new dedicated doc. Add SSR row to SKILL.md routing table.
* docs: add disclaimer of new package
* docs: extend explanation on keys env vars
* docs: add platform-specific quick starts to SKILL.md
Split the single generic example into per-platform sections
(Edge Functions, Cloudflare Workers, Hono, SSR Frameworks) so
AI agents pick the correct import specifier for each runtime.
Adds npm: prefix to all Deno examples and a Deno column to the
entry points table. Also adds createSupabaseContext examples.
* docs: add server-to-server quick starts and allow:always guardrails
Add secret key auth and webhook signature verification quick starts
to SKILL.md. Add explicit decision tree for allow:'always' so AI
agents confirm with the user before leaving endpoints unprotected.
* docs: add legacy keys warning, skills install, remove webhook docs
- Add legacy keys warning to SKILL.md (avoid anon/service_role keys)
- Add AI coding skills install section to README
- Add server-to-server quick start with caller code to README
- Add runtimes, documentation table, and named secret keys to README
- Remove verifyWebhookSignature references from all docs
- Delete docs/webhooks.md (code removal in separate PR)
* docs: add verify_jwt = false note for non-user auth modes
Edge Functions require verify_jwt = false in config.toml when
using allow: public, secret, or always — otherwise the platform
rejects requests before the handler runs.
* docs: add edge function recipes and refactor env vars doc
Add recipes for function-to-function calls, pg_net from database,
Stripe webhooks, and generic webhook signature verification.
Document the @supabase/server/wrappers entry point.
Refactor environment-variables.md into Supabase vs non-Supabase sections.
* docs: add security doc covering timing-safe comparison, auth model, CORS
* docs: link auth-modes timing-safe mentions to security.md
* docs: adding 'local cli' to secrets table
This envs will be injected from cli too
* docs: setting Deno as first installation choice
* docs: adding 'verify_jwt=false' disclaimer for non-user auth
* docs: split Deno/Supabase runtime section, merge Deno/Node/Bun
* docs(skills): adding legacy code migration example
* docs(skills): explaining why legacy code should be migrated
* docs: rewrite migration section, improve skill description triggers
---------
Co-authored-by: Kalleby Santos <kalleby_santos@hotmail.com>
6.3 KiB
Supabase environments (zero config)
On Supabase Platform and Local Development (CLI), all variables are auto-provisioned — no configuration needed
| Variable | Format | Description | Available in |
|---|---|---|---|
SUPABASE_URL |
https://<ref>.supabase.co |
Your Supabase project URL | All |
SUPABASE_PUBLISHABLE_KEYS |
{"default":"sb_publishable_..."} |
Named publishable keys as JSON object | Platform, Local Development (CLI) |
SUPABASE_SECRET_KEYS |
{"default":"sb_secret_..."} |
Named secret keys as JSON object | Platform, Local Development (CLI) |
SUPABASE_JWKS |
{"keys":[...]} or [...] |
JSON Web Key Set for JWT verification | Platform, Local Development (CLI) |
SUPABASE_PUBLISHABLE_KEY |
sb_publishable_... |
Single publishable key (fallback) | Self-hosted |
SUPABASE_SECRET_KEY |
sb_secret_... |
Single secret key (fallback) | Self-hosted |
Non-Supabase environments (Node.js, Bun, Cloudflare, self-hosted)
Set these based on which auth modes your app uses:
| Variable | Required when |
|---|---|
SUPABASE_URL |
Always |
SUPABASE_SECRET_KEY |
allow: 'secret' or using supabaseAdmin |
SUPABASE_PUBLISHABLE_KEY |
allow: 'public' |
SUPABASE_JWKS |
allow: 'user' (JWT verification) |
Minimal .env example
SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_SECRET_KEY=sb_secret_...
SUPABASE_PUBLISHABLE_KEY=sb_publishable_...
SUPABASE_JWKS={"keys":[...]}
Plural vs singular keys
The SDK checks the plural form first (SUPABASE_PUBLISHABLE_KEYS), then falls back to the singular form (SUPABASE_PUBLISHABLE_KEY). The same applies to secret keys.
Plural form — named keys as a JSON object
Use this when you have multiple keys for different clients (web, mobile, internal):
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"}
You can then validate against specific keys with named key syntax:
// Only accept the "web" publishable key
withSupabase({ allow: 'public:web' }, handler)
// Accept any secret key
withSupabase({ allow: 'secret:*' }, handler)
Singular form — equivalent to a single "default" key
SUPABASE_PUBLISHABLE_KEY=sb_publishable_default_abc
SUPABASE_SECRET_KEY=sb_secret_default_abc
This is equivalent to setting the plural form with a single "default" entry:
# These two are the same:
SUPABASE_PUBLISHABLE_KEY=sb_publishable_default_abc
SUPABASE_PUBLISHABLE_KEYS={"default":"sb_publishable_default_abc"}
The singular form is a convenience for the common case where you only have one key. The SDK stores it internally as { default: "<value>" }, so allow: 'public' (which looks for the "default" key) works with both forms.
Priority
When both singular and plural forms are set, the plural form takes priority.
JWKS format
SUPABASE_JWKS accepts two formats:
# Standard JWKS format
SUPABASE_JWKS={"keys":[{"kty":"RSA","n":"...","e":"AQAB"}]}
# Bare array (convenience)
SUPABASE_JWKS=[{"kty":"RSA","n":"...","e":"AQAB"}]
When SUPABASE_JWKS is not set, JWT verification (allow: 'user') is unavailable.
Runtime-specific behavior
The SDK reads environment variables using this priority:
Deno.env.get(name)— Deno (including Supabase Edge Functions)process.env[name]— Node.js, Bun, Cloudflare Workers (with node-compat)
Supabase Edge Functions
Environment variables are auto-provisioned by the platform. Nothing to configure.
Deno / Node.js / Bun
Set variables via .env files (with a loader like dotenv for Node.js) or your deployment platform's environment configuration.
Cloudflare Workers
Cloudflare Workers don't expose Deno.env or process.env by default. Two options:
-
Enable node-compat in
wrangler.toml:compatibility_flags = ["nodejs_compat"] -
Pass overrides via the
envconfig option:withSupabase( { allow: 'user', env: { url: env.SUPABASE_URL, publishableKeys: { default: env.SUPABASE_PUBLISHABLE_KEY }, secretKeys: { default: env.SUPABASE_SECRET_KEY }, }, }, handler, )
Using env overrides
The env option on withSupabase, createSupabaseContext, and core primitives lets you override auto-detected values. Partial overrides are merged with what's resolved from environment variables:
import { withSupabase } from '@supabase/server'
export default {
fetch: withSupabase(
{
allow: 'user',
env: {
url: 'http://localhost:54321', // override just the URL
},
},
handler,
),
}
Using resolveEnv directly
For manual environment resolution — useful in tests, custom setups, or debugging:
import { resolveEnv } from '@supabase/server/core'
const { data: env, error } = resolveEnv()
if (error) {
console.error(`Missing config: ${error.message}`)
}
// With overrides
const { data: envOverridden } = resolveEnv({
url: 'http://localhost:54321',
publishableKeys: { default: 'test-key' },
})
resolveEnv returns a SupabaseEnv object:
interface SupabaseEnv {
url: string
publishableKeys: Record<string, string>
secretKeys: Record<string, string>
jwks: JsonWebKeySet | null
}
Graceful parsing
Malformed JSON in environment variables doesn't throw — the SDK falls back to empty values:
- Malformed
SUPABASE_PUBLISHABLE_KEYSorSUPABASE_SECRET_KEYS→ empty{} - Malformed
SUPABASE_JWKS→null(JWT verification unavailable) - Missing
SUPABASE_URL→EnvError(this is the only hard requirement)