Connect Supabase from Workers: supabase-js or Hyperdrive
Use @supabase/supabase-js over PostgREST, or Hyperdrive pooled direct Postgres; choose by query frequency and cold-start requirements.
Edited and verified by Orange Book Editorial Team ·
Bottom line first
When you use Supabase table APIs, Auth, or Storage, pick @supabase/supabase-js (HTTP/PostgREST, naturally suited to Workers). When you need raw SQL, connection pooling, and lower latency, use Hyperdrive plus postgres.js for a direct Postgres connection.
Choosing between the two paths
| Path | Best for | Key limits |
|---|---|---|
@supabase/supabase-js | Table queries, row-level security (RLS), Auth, Storage — the full Supabase feature set | Goes through PostgREST; expressiveness is limited by the API; no pooling benefit |
Hyperdrive + postgres.js | Raw SQL, complex transactions, frequent short queries | Requires a Hyperdrive configuration; no LISTEN/NOTIFY or advisory locks |
Supabase free-plan projects pause automatically after roughly 7 days of inactivity (they can be restored). While paused, both paths fail, so check project status in the Supabase dashboard first when troubleshooting.
Path one: supabase-js
npm i @supabase/supabase-js
npx wrangler secret put SUPABASE_URL
npx wrangler secret put SUPABASE_SERVICE_ROLE_KEYSUPABASE_URL looks like https://<project-ref>.supabase.co; the service role key lives in the API settings of the Supabase dashboard. The service key bypasses RLS — keep it in a server-side secret only, never in a frontend bundle.
import { createClient } from '@supabase/supabase-js';
interface Env {
SUPABASE_URL: string;
SUPABASE_SERVICE_ROLE_KEY: string;
}
export default {
async fetch(request, env: Env): Promise<Response> {
const supabase = createClient(env.SUPABASE_URL, env.SUPABASE_SERVICE_ROLE_KEY);
const { data, error } = await supabase.from('notes').select('id,title').limit(10);
if (error) {
return Response.json({ error: error.message }, { status: 502 });
}
return Response.json({ notes: data });
},
};This path needs no Wrangler binding at all; beyond the secrets there is no extra configuration.
Path two: Hyperdrive direct Postgres
Get the direct connection string from the Supabase dashboard, shaped like postgres://USER:PASSWORD@HOST:PORT/postgres, then create the Hyperdrive configuration:
npx wrangler hyperdrive create supabase-pg --connection-string="postgres://USER:PASSWORD@HOST:PORT/postgres"{
"name": "notes-api",
"compatibility_date": "2026-08-25",
"compatibility_flags": ["nodejs_compat"],
"hyperdrive": [
{ "binding": "HYPERDRIVE", "id": "<id returned by the create command>" }
]
}import { Client } from 'pg';
interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env: Env): Promise<Response> {
const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });
try {
await client.connect();
const result = await client.query('SELECT id, title FROM notes LIMIT 10');
return Response.json({ notes: result.rows });
} catch (error) {
return Response.json({ error: String(error) }, { status: 502 });
} finally {
await client.end().catch(() => {});
}
},
};With postgres.js the idea is identical — swap in env.HYPERDRIVE.connectionString. Hyperdrive enforces TLS, which Supabase satisfies by default.
Verification and troubleshooting
After deploying, walk the endpoint with curl:
curl -s https://<worker>.workers.dev/notes| Symptom | Check first | Recovery |
|---|---|---|
502 with a fetch failure | Whether the Supabase project was auto-paused | Restore the project in the dashboard and retry |
401/403 | Whether the service role key was mistyped or rotated | Rewrite it with wrangler secret put and redeploy |
| Hyperdrive path cannot connect | Whether HOST/PORT point to the direct endpoint instead of the pooled one | Rebuild Hyperdrive with the direct connection string from the dashboard |
SQL errors mentioning LISTEN | Whether the code uses a feature Hyperdrive does not support | Switch to polling or supabase-js Realtime |
Remote boundary and rollback
Creating a Hyperdrive configuration, writing Supabase secrets, and deploying the Worker all change Cloudflare- or Supabase-side state; this tutorial does not run those actions. Rollback: remove the hyperdrive binding from wrangler.jsonc and redeploy, then delete the configuration with wrangler hyperdrive delete <id>. If you rotated the service role key, regenerate it in the Supabase dashboard and invalidate the old value. Business data is unaffected by a code rollback and needs no restore.
Next: connect Neon from Workers. General binding and secret rules live in Bindings, environments, and secrets.
Primary sources
Did this page help you complete your goal?
Beta feedback is generated in this browser and is never uploaded automatically.
External database integrations: D1, Hyperdrive, or the official driver
Before connecting an external database from Workers, decide whether D1 is enough, then choose between Hyperdrive pooled TCP and the database's official HTTP driver.
Connect Neon from Workers: Hyperdrive first, serverless driver as fallback
Neon officially recommends pooled connections through Hyperdrive; lightweight cases can use @neondatabase/serverless over HTTP or WebSocket.