Skip to Content
DocumentationSelf-host1. Set up Supabase

1. Set up Supabase

Everything the web UI and agent need — schema, storage bucket, realtime policies, and a login user — is created by one script, in one run, against a fresh project.

Create a project

Create a project at supabase.com/dashboard . The free tier is enough. A fresh, empty Postgres is what the script expects.

Collect four values

From Project Settings → API Keys:

  • Project URL — https://[REF].supabase.co
  • Publishable key — sb_publishable_…
  • Secret key — sb_secret_… (keep it secret; create one if none is listed)

Older projects show anon and service_role instead — the legacy names for the same two slots. Pass them in the same variables. Projects created after 2025-11-01 only get the new format.

From Settings → Database → Connection string, a Postgres URL. Pick one:

PathWhenForm
DirectYour machine has IPv6postgresql://postgres:[PW]@db.[REF].supabase.co:5432/postgres
Pooler (session mode)IPv4-only networkspostgresql://postgres.[REF]:[PW]@aws-[REGION].pooler.supabase.com:5432/postgres

Use session mode (port 5432), not transaction mode (6543) — the init schema’s session settings must persist across its statements.

Run the script

You need psql and curl on your machine, and a clone of the repo.

SUPABASE_URL=https://[REF].supabase.co \ DB_URL="postgresql://postgres:[PW]@db.[REF].supabase.co:5432/postgres" \ SECRET_KEY=sb_secret_... \ PUBLISHABLE_KEY=sb_publishable_... \ ./scripts/setup-supabase.sh

The script is idempotent — every statement is if not exists / on conflict do nothing, so re-running is always safe and is the standard fix for a half-finished setup.

Keep the output

It prints two blocks: a WEB env block and an AGENT/CLI config block. You need both in the next two steps.

What it created

  1. The schema — tables, RPCs, indexes, triggers, RLS, grants, and the realtime publication.
  2. The images storage bucket + its RLS policy, so agents can offload image bytes instead of broadcasting them.
  3. Realtime private-channel policies. A fresh project ships realtime.messages with RLS on and no policies, so private:{userId} channels would fail to join. These authorize each user to their own topics.
  4. A confirmed login user — email/password, so you can sign in without configuring any OAuth provider.
  5. A JWT signer probe — it detects whether your project verifies ES256 or the legacy HS256 secret, and prints only the line you need.

Expected noise. Step 1 prints ~20 WARNING: no privileges were granted for "…similarity…" lines. Harmless: pg_trgm lives in public, so the blanket grant sweeps functions that belong to the extension rather than to you. Trigram search still works.

Deliberately left out

Not gaps — decisions. OAuth providers, SMTP, email templates, and redirect URLs are dashboard settings with no SQL surface; the seeded email/password login exists precisely so none of them block first use. No row data is seeded.


Reference: the full walkthrough — every input, the API-key generations and why they are not just a rename, and the failure mode of each step — is in docs/reference/setup-supabase.md. The schema contract itself is docs/reference/database.md.

Last updated on