Postgres backend provider
Status: NEXT_PUBLIC_BACKEND_PROVIDER=postgres selects the server-side
blob registry and nothing else. It is not the self-hosting switch, and it
gives the browser no data layer.
Table data already runs on self-hosted Postgres — through PostgREST, which the
browser repositories speak natively, so the cutover is one address:
NEXT_PUBLIC_DATA_URL. See oracle-shift-guide.md.
Supabase remains the identity provider either way.
A second, direct-pg set of repositories used to live under
backend/providers/postgres/repositories/. It was never imported by anything
that shipped: wire-backend.ts reached a stub that threw, because the pg
driver cannot run in a browser bundle. It was deleted rather than maintained as
a duplicate of the live path; git log has it if the app ever needs to talk to
Postgres without PostgREST in front.
What is live
| Item | Location |
|---|---|
pg pool + RLS session (request.jwt.claim.sub) |
backend/providers/postgres/pool.ts, pg-runner.ts |
| Blob registry | storage/providers/postgres/blob-registry.ts |
| Tiered blob API | storage/server/blob-api.ts picks the Postgres registry when backend = postgres |
| Self-host auth stubs | supabase/migrations-self-hosted-postgres/0025_self_host_auth.sql |
Server-side blob registry
Server-only, since it uses the Node pg driver:
NEXT_PUBLIC_BACKEND_PROVIDER=postgres
DATABASE_URL=postgres://user:pass@localhost:5432/thesis
NEXT_PUBLIC_BLOB_PROVIDER=tiered
# Auth and table data still Supabase-shaped:
NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
# R2 for hot tier (see docs/running/storage/r2-setup.md)
Order matters. Apply
supabase/migrations-self-hosted-postgres/
first, then every file in supabase/migrations/. A stock Postgres
has none of the furniture Supabase provides implicitly — auth.users in a foreign key, auth.uid()
in every RLS policy, storage.buckets, the anon/authenticated/service_role grants — and the
base chain uses it from the first file, so 0001_papers.sql fails on line 28 and nothing after it
runs. This paragraph used to give the two in the opposite order.
0025 creates a minimal auth.users stub with RLS enabled and no
policies; sync user ids from Supabase via service role or direct postgres.
Scheduled maintenance
Two jobs are deployment configuration rather than application code, and one of
them has to run or the chunk archive stays empty: see
metrics-maintenance.md for the commands, a
suggested cron schedule, and the queries that show whether it is working.