11ai supabase setup
Version baseline: Supabase CLI v2, supabase-js v2, and the current CLI local Postgres 17 line. Inspect the linked project, installed client patch, CLI patch, and remote Postgres version before changing configuration or migrations.
Two things here change shared state: linking a directory to a remote project, and writing environment files that hold keys. Confirm which remote project is intended before linking, because once a link exists several commands act on that project rather than on the local stack.
Check what exists
supabase --version
docker info --format '{{.ServerVersion}}' 2>/dev/null || echo "docker unavailable"
ls -la supabase/ 2>/dev/null
Use 11ai-operator-supabase-environment for the full inspection. If a supabase/ directory already exists, this is not a fresh setup — change only what is missing rather than re-initializing over someone's migrations.
Docker is a prerequisite for the local stack, not for the CLI. Install and start it first if the local stack is wanted.
Install and initialize
brew install supabase/tap/supabase
supabase login
supabase init
Install the CLI through a package manager or as a project dev dependency; do not install it globally with npm, which the project's own tooling then cannot pin. supabase login opens a browser and stores a personal access token — never take a token through the terminal.
supabase init creates supabase/config.toml and the migrations directory. It is safe and local.
Read references/setup.md for the per-platform installs, the config file settings worth knowing, the environment file shapes for each framework, the client factory patterns, and the type generation step.
Link deliberately
supabase projects list
supabase link --project-ref PROJECT_REF
Read the project list and confirm the name and reference with the user before linking. After linking, supabase db push, supabase db diff --linked, supabase functions deploy, and supabase secrets set all act on that remote project — so linking a production project makes a mistyped command a production change.
Prefer linking a development or staging project. When production must be linked, say so plainly and treat every subsequent command as production-facing.
Start the local stack and write the environment
supabase start
supabase status
supabase start pulls several container images on first run and prints the local API URL, database URL, and keys. Those local keys are fixed development values shared by every Supabase project, so they are not secrets — but the file they go into should still be ignored, so the same file can hold real values later.
Write two things, and keep them apart:
- An ignored environment file with the URL, the anon key, and — only if a server needs it — the service role key.
- A committed
.env.examplewith the variable names and no values.
grep -q '^\.env' .gitignore || echo "env files are NOT ignored"
The anon key belongs in the browser and is protected by row level security. The service role key bypasses row level security completely and must never reach client code, a NEXT_PUBLIC_ variable, or a committed file. Create the server client in a server-only module and never import it from a component.
Enable row level security on every table as part of setup, not later. A table without it is readable and writable by anyone holding the anon key, which is published in the browser. Hand the policies to 11ai-operator-supabase-rls.
Verify
supabase status
supabase migration list
supabase gen types typescript --local > src/database.types.ts
npx tsc --noEmit
Then prove the application connects: start it, perform one read through the anon client, and confirm it returns data or a policy denial rather than a connection error. Confirm the reverse too — that a table with row level security on and no policy returns no rows to the anon key. That negative check is what tells you the protection is actually on.
Guardrails
- Never print a service role key, a database password, a personal access token, or the contents of an environment file. Confirm a variable by name.
- Never commit an environment file, and never prefix a service role key with
NEXT_PUBLIC_or any client-exposed prefix. - Do not run
supabase db pushduring setup. Pushing migrations to a linked project is a separate, reviewed step in11ai-operator-supabase-migrations. - Do not run
supabase db resetagainst anything but the local stack; it drops the database and replays migrations. - Do not use
supabase stop --no-backupunless the local data is genuinely disposable. - Do not create a table without enabling row level security on it.
- Report the CLI version, whether Docker is available, the linked project reference and name, the local stack URLs, the variable names written to which files, whether those files are ignored, the generated types path, and the verification result including the negative row level security check.