UXDL Docs

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

bash
pnpm add @supabase/supabase-js

Server client (service role)

Use the service role key on the backend only — it bypasses RLS. Never expose it to clients.

typescript
// 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

dotenv
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...    # Server only — vault
SUPABASE_ANON_KEY=eyJ...            # Client-side only

Querying data

typescript
// 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.

sql
-- 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.

typescript
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 whenUse PostgreSQL + Drizzle/Sequelize when
You want managed Postgres + dashboardYou need full control over DB infra
Client apps query DB directly with RLSAll access goes through Express API
You need Supabase Auth or StorageYou use Cognito for auth
Prototyping / internal toolsHigh-traffic production API services

Official documentation