Supabase
Supabase is hosted Postgres, so the @db-x/postgres-library
components apply unchanged. What makes a schema Supabase is two things DB-X
has no dedicated component for yet: a foreign key into the managed
auth.users table, and Row Level Security.
Runnable example: examples/supabase.
DB-X is an early prototype. Do not point it at a project you care about.
Connect
Point <DatabaseTarget> at the project's Postgres connection string — the
local stack from the Supabase CLI, or a hosted project:
brew install supabase/tap/supabase # or https://supabase.com/docs/guides/cli
supabase init # once
supabase start # Postgres on :54322, plus auth/API/Studio
Ownership and RLS
There is no <ForeignKey> or <Policy> component, so both go through a
<SeedData> block of idempotent raw SQL — DROP … IF EXISTS before each
CREATE, so re-applying is safe:
<Table name="todos">
<Column name="id" type="uuid" primaryKey default="gen_random_uuid()" />
<Column name="user_id" type="uuid" notNull />
<Column name="title" type="citext" notNull />
</Table>
<SeedData
name="rls-and-ownership"
dependsOn={['table:todos']}
sql={`
ALTER TABLE todos DROP CONSTRAINT IF EXISTS todos_user_id_fkey;
ALTER TABLE todos ADD CONSTRAINT todos_user_id_fkey
FOREIGN KEY (user_id) REFERENCES auth.users (id) ON DELETE CASCADE;
ALTER TABLE todos ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Users manage their own todos" ON todos;
CREATE POLICY "Users manage their own todos" ON todos
FOR ALL USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);
`}
/>
dependsOn is doing real work here. A seed's SQL is opaque to the runtime, so
naming the table is the only way it knows this block is downstream of todos —
which buys both the ordering and a re-run if that table is ever rebuilt, since a
recreated table comes back without its policy.
Things worth knowing
auth.usersis not yours to manage. Reference it; never declare it. It belongs to Supabase's own migrations.- RLS is off until you enable it. A table without
ENABLE ROW LEVEL SECURITYis readable by any authenticated client through the API. Enabling it with no policy denies everyone instead — both halves have to land. citextneeds its extension. Declare<Extension name="citext" />before a column that uses it.
Safety
Identical to PostgreSQL: destructive changes need
--allow-destructive, <Postgres protect> refuses them outright, and a
pg_dump snapshot is captured first. Against a hosted project the default
schema snapshot mode is the safer default — full holds a transaction open
for the length of the dump.
Next
- PostgreSQL — the underlying library.
- CockroachDB — the other Postgres-compatible target.