Supabase
Connect to Supabase Postgres directly or via supabase-js from Deno, covering pooler ports, RLS, Edge Functions, and secret boundaries
There are two ways in: treat Supabase as managed Postgres and connect directly (with Drizzle/postgres.js—see PostgreSQL and Drizzle), or use the official SDK @supabase/supabase-js against the PostgREST/Auth/Storage APIs. The SDK is published on both npm and JSR (jsr:@supabase/supabase-js).
import { createClient } from "jsr:@supabase/supabase-js@2";
const url = Deno.env.get("SUPABASE_URL");
const key = Deno.env.get("SUPABASE_PUBLISHABLE_KEY");
if (!url || !key) throw new Error("SUPABASE_URL / SUPABASE_PUBLISHABLE_KEY required");
export const supabase = createClient(url, key);
deno run \
--allow-env=SUPABASE_URL,SUPABASE_PUBLISHABLE_KEY \
--allow-net=<project-ref>.supabase.co \
src/main.ts
Direct Postgres connections and pooling
Supabase offers several connection methods; ports and use cases per the official docs:
| Method | Host:port | Use for |
|---|---|---|
| Direct connection | db.<project-ref>.supabase.co:5432 | persistent servers, migrations, pg_dump; IPv6 (IPv4 requires a paid add-on) |
| Supavisor session mode | aws-<region>.pooler.supabase.com:5432 | fallback for IPv4-only networks |
| Supavisor transaction mode | aws-<region>.pooler.supabase.com:6543 | serverless / edge functions with many short-lived connections |
- For environments without persistent processes (such as Deno Deploy), use transaction mode (6543). The docs state transaction mode does not support prepared statements—disable them in your client (
postgres.js:postgres(url, { prepare: false })). - Under serverless concurrency, budget total connections against the maximum instance count, not a single instance.
- Run migrations over a direct or session-mode connection as a separate release step; never grant schema mutation to the production HTTP process.
deno run \
--allow-env=DATABASE_URL \
--allow-net=aws-<region>.pooler.supabase.com:6543 \
src/main.ts
Auth and RLS boundaries
- The SDK acts as the caller: with the new publishable key (the counterpart of the legacy anon JWT key — the two are distinct key types that can coexist, not a simple rename) plus a user JWT, PostgREST operates under that user's role and RLS policies apply.
- The official RLS docs require RLS on every table in an exposed schema (
publicby default); once enabled, the API serves nothing to publishable-key requests until policies exist. Tables created in the Table Editor get RLS automatically; tables created via raw SQL need an explicitenable row level security. - The new secret key (the counterpart of the legacy service_role JWT key) bypasses RLS, and the docs forbid shipping it to browsers or customers. Keep it server-side only, injected from the environment, out of logs.
- If your Deno backend only makes trusted service-to-service calls, a direct Postgres connection is usually simpler than service key + PostgREST. Reach for the SDK + RLS when you need per-end-user authorization.
Edge Functions vs. local Deno
Supabase Edge Functions run on the Supabase Edge Runtime, which the docs describe as a Deno-compatible, TypeScript-first runtime (open source at github.com/supabase/edge-runtime). Practical differences from local Deno:
- Imports support
npm:,jsr:, and Node built-ins; the docs recommend a dedicateddeno.jsonper function and warn against sharing one global config across/supabase/functionsfor deployment. - Use
supabase functions servelocally for a runtime close to production, andsupabase functions deployto ship. - Functions are designed for short-lived, idempotent work and can cold-start; move long-running jobs to background workers instead.
- It is a Deno-compatible runtime, not Deno itself—do not assume feature parity with your local
denoversion; check the Edge Runtime repo before relying on newer APIs.
Secret management
- Do not introduce the secret key where publishable-key access suffices; keep the two under distinct environment variable names to prevent mix-ups.
- Load secrets only from the environment or a secret store—never source, logs, or error responses—and rotate using Supabase's key-rolling flow in the dashboard.
- Scope
--allow-envto exact variable names and--allow-netto the project host; add--no-promptin CI.
Official references: Connecting to your database, Row Level Security, Edge Functions, Function dependencies, Deno's official Supabase example.