Supabase
Supabase client, Postgres via Supabase, RLS, and realtime.
Supabase provides managed PostgreSQL with built-in auth, storage, and realtime subscriptions. Use it when you want Postgres without managing infrastructure, or when you need Row Level Security (RLS) at the database layer.
Install
pnpm add @supabase/supabase-jsServer client (service role)
Use the service role key on the backend only — it bypasses RLS. Never expose it to clients.
// src/lib/supabase.ts
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{ auth: { autoRefreshToken: false, persistSession: false } },
);Environment
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ... # Server only — vault
SUPABASE_ANON_KEY=eyJ... # Client-side onlyQuerying data
// src/services/projects.service.ts
import { supabase } from "../lib/supabase";
export async function listProjects(userId: string) {
const { data, error } = await supabase
.from("projects")
.select("id, name, created_at")
.eq("owner_id", userId)
.order("created_at", { ascending: false });
if (error) throw error;
return data;
}
export async function createProject(name: string, ownerId: string) {
const { data, error } = await supabase
.from("projects")
.insert({ name, owner_id: ownerId })
.select()
.single();
if (error) throw error;
return data;
}Row Level Security (RLS)
Enable RLS on tables accessed by client-side Supabase clients. Backend service role bypasses RLS — enforce authorization in your Express middleware instead.
-- Example RLS policy (applied in Supabase dashboard or migration)
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own projects"
ON projects FOR SELECT
USING (auth.uid() = owner_id);Realtime subscriptions
Supabase has built-in realtime. For WebSocket needs within Express services, prefer Socket.io. Use Supabase realtime when the client talks directly to Supabase.
const channel = supabase
.channel("project-changes")
.on("postgres_changes", { event: "*", schema: "public", table: "projects" }, (payload) => {
console.log("Change:", payload);
})
.subscribe();When to use Supabase vs raw PostgreSQL
| Use Supabase when | Use PostgreSQL + Drizzle/Sequelize when |
|---|---|
| You want managed Postgres + dashboard | You need full control over DB infra |
| Client apps query DB directly with RLS | All access goes through Express API |
| You need Supabase Auth or Storage | You use Cognito for auth |
| Prototyping / internal tools | High-traffic production API services |