This guide focuses on local Supabase (Docker + CLI). For branching, migrations, and the GitHub integration, use the canonical guide: docs/developers/Supabase.md.
This guide covers setting up the Supabase CLI for team development, including installation and local development workflow.
- Sources
- Prerequisites
- Docker Installation
- CLI Installation
- Environment Files
- Secrets & Encryption
- Commands
- Project Setup
- Local Development
- Troubleshooting
- Useful Scripts
- Do Not Use
Official Documentation
Local Branching YT video
Make sure you have the following things:
- Installed Docker
- Installed Supabase CLI
- The supabase DB password/env vars - Ask a fellow developer
To use the supabase CLI, make sure you have installed docker prior.
After installing, make sure to configure docker in the settings:
brew install supabase# Or install globally
npm install -g supabaseDownload the latest release from the Supabase CLI releases page and add it to your PATH.
supabase --versionTo switch between live Supabase and your local Supabase CLI instance, prepare both files:
-
.env.local— Live/hosted Supabase- Contains live project values (project id, anon key, service role key, JWT secret, etc.).
- Used by scripts:
npm run dev:live,npm run frontend:live,npm run backend:live.
-
.env.supabase.local— Local Supabase (CLI)- Contains local values printed by the Supabase CLI after you start it (API URL, keys, studio URL, etc.).
- Used by scripts:
npm run dev:local,npm run frontend:local,npm run backend:local.
Templates:
- Copy
.env.local.template→.env.localand fill live keys. - Copy
.env.supabase.local.template→.env.supabase.localand fill the local values.
Tip: Start local Supabase with npm run s:start; the CLI prints the local API URL, studio URL, and publishable/secret keys you can use in .env.supabase.local.
Note on encrypted secrets
- The file
supabase/.env.keysstores private decryption keys for values encrypted insupabase/.env.productionand.env.preview(e.g., Google OAuth secret). It’s not required for local‑only development. See Secrets & Encryption (Secrets & Encryption).
| Purpose | Script | Env file |
|---|---|---|
| Live app (both) | npm run dev:live |
.env.local |
| Live frontend | npm run frontend:live |
.env.local |
| Live backend | npm run backend:live |
.env.local |
| Local app (both) | npm run dev:local |
.env.supabase.local |
| Local frontend | npm run frontend:local |
.env.supabase.local |
| Local backend | npm run backend:local |
.env.supabase.local |
| Start local Supabase | npm run s:start |
.env.supabase.local |
| Restart local Supabase | npm run s:restart |
.env.supabase.local |
| Reset local DB | npm run s:reset |
.env.supabase.local |
We use dotenvx to encrypt sensitive values (e.g., Google OAuth client secret) inside the Supabase environment files:
supabase/.env.productionandsupabase/.env.previewmay contain values likeSUPABASE_AUTH_EXTERNAL_GOOGLE_SECRET="encrypted:...".- The decryption keys live in
supabase/.env.keysand are ignored by Git (seesupabase/.gitignore). Keep this file private.
How it works
- Our link scripts (
npm run s:link:prod,npm run s:link:dev) usedotenvx run -f ...to load the env file, automatically decrypting anyencrypted:values using the matching key fromsupabase/.env.keys. supabase/config.tomlreadsSUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_IDandSUPABASE_AUTH_EXTERNAL_GOOGLE_SECRETviaenv(...)for the Google provider configuration.
Updating encrypted secrets
- To update the encrypted Google secret, edit
supabase/.env.productionor.env.previewand re‑encrypt using dotenvx per their docs. Ensure the corresponding private key insupabase/.env.keysmatches. - Do not commit real secrets or private keys to Git.
Uploading secrets to Supabase
- If you need Supabase to hold certain envs for CLI/functions, upload only the required variables (e.g., decrypted provider secrets), not the private decryption keys. Example:
# Upload env vars from a file (choose only the needed ones)
npx supabase secrets set --env-file supabase/.env.productionWarning: Avoid uploading supabase/.env.keys to Supabase secrets. Those keys are for local decryption only.
To get a full list of commands you can run supabase. If "supabase is not found", prefix it as such: npx supabase.
To find out more about any command run npx supabase [command] --help and the terminal will provide more information.
npm run dev- Start frontend + backend (remote DB)npm run dev:local- Start local Supabase + frontend + backendnpm run dev:live- Start frontend + backend with live environmentnpm run frontend- Start only frontendnpm run backend- Start only backendnpm run frontend:local- Start frontend with local Supabase environmentnpm run frontend:live- Start frontend with live environmentnpm run backend:local- Start backend with local Supabase environmentnpm run backend:live- Start backend with live environmentnpm run install-all- Install dependencies for all packages (root, frontend, backend)
npm run s:start- Start local Supabase stacknpm run s:stop- Stop local Supabase stacknpm run s:restart- Restart local Supabase stacknpm run s:status- Show status of local servicesnpm run s:studio- Open Supabase Studionpm run s:link- Link project to Supabase
npm run s:reset- Reset local DB and apply all migrationsnpm run s:seed:main- Create/refresh seed data from mainnpm run s:dump- Dump database schema to file
Homebrew
supabase login # (Homebrew install)Global
npx supabase loginProject ref: rcbddkhvysexkvgqpcud
Script:
npm run s:link:prodProject ref: kpqrzaisoyxqillzpbms
Script:
npm run s:link:devnpm run s:start
## Or
supabase start # Add npx in front if using global
If you want to start your local database with seed data from production you can run:
npm run s:seed:main
npm run s:resetLocal changes are done using migration files. They contain SQL which is applied to your local supabase instance.
Important! When running local supabase, make sure you use the local development environment.
## Run the frontend locally
npm run frontend:local
## Run the backend locally
npm run backend:local
## Or run both from one terminal if you prefer
npm run dev:localAfter creating your new table, restart the containers to view them locally using
npm run s:resetThis will apply your new migration and you will be able to see it in the studio
Create a new migration with a descriptive, underscore‑separated name:
npm run s:migration:new my_feature_or_fix_nameThis creates a new file under supabase/migrations/. Add your SQL there. To validate locally, rebuild your local DB:
npm run s:resetIf needed, regenerate local types for the app:
npm run generate:types:local- Our Supabase project is set up with Branching. Changes to the
supabase/folder in a PR trigger the Supabase workflow (provided by Supabase, not custom). - Typical flow:
- Commit your migration(s) under
supabase/migrations/. - Open a PR on GitHub. Ensure the Supabase workflow/checks pass.
- If
supabase db resetworks locally without issues, it’s a good indicator the workflow will succeed. - Merge into
developwhen the workflow passes. The persistentdevelopSupabase branch is updated with the new SQL. - Later, changes are merged to
mainfor production. OurmainSupabase branch mirrors the GitHubmainbranch.
- Commit your migration(s) under
Important: We do not run manual pushes. Do not use supabase db push or any s:db:push... scripts for schema. Let the GitHub integration apply migrations.
Reset the branch in the Supabase UI, then the migrations should run properly.
Sometimes you will get odd errors about connections failing when doing a db reset, If this happens restart your local supabase instance and try to reset again.
supabase stop && supabase start
# or
npm run s:restartSometimes if you are switching back and forth between using npm run s: commands and supabasecommands, you will get an error about the port being allocated already. If this happens try stopping the container that it suggests
npx supabase stop --project-id <project-id>
# or
supabase stop --project-id <project-id>If this does not help you might need to delete all of your supabase containers before starting the server again. Warning: This will remove all data from your current local containers.
npm run s:stop
# or
supabase stop
docker volume ls --filter "name=supabase" -q | xargs -r docker volume rm
# Then start your local supabase again with your prefered commandWarning Never edit previously merged migration files.
Migrations are read from top-to-bottom. If something needs changing, create a new migration to fix/adjust prior work. Editing old migrations after a PR is opened or merged can break the branching workflow.
If the CLI complains about linking just run:
npm run s:link:prod
## or
supabase link --project-ref rcbddkhvysexkvgqpcud- Start/restart/status/studio
npm run s:start
npm run s:restart
npm run s:status
npm run s:studio- Migrations
npm run s:migration:new my_change
npm run s:reset- Types
npm run generate:types:local
npm run generate:types # Generates the types from the supabase main branchsupabase db pushnpm run s:db:push:prod/npm run s:db:push:preview
These are not part of our branching workflow. Always rely on the GitHub integration to apply migrations.

