Local Supabase Management
Critical rules and patterns for working with Supabase locally.
Critical Rules
ALWAYS Use npx
# CORRECT - Always use npx
npx supabase start
npx supabase stop
npx supabase status
npx supabase migration new
npx supabase db push --local
# WRONG - Never use brew-installed supabase
supabase start # NO!
ALWAYS Create Migrations Properly
# CORRECT - Use the CLI to generate migration files
npx supabase migration new add_user_profiles
# This creates: supabase/migrations/TIMESTAMP_add_user_profiles.sql
# Then edit that file with your SQL
ALWAYS Push Locally
# CORRECT - Apply migrations to local database
npx supabase db push --local
# WRONG - This resets your data!
npx supabase db reset # NEVER unless explicitly asked
NEVER Use db reset
npx supabase db reset destroys all local data. Only use when:
- User explicitly requests it
- You warn them data will be lost
- They confirm
Custom Port Configuration
Every project needs unique ports to avoid conflicts when running multiple Supabase instances.
Port Range Pattern
Use a unique 5-digit prefix for each project:
| Project | API | DB | Studio | Inbucket | Storage | |---------|-----|-----|--------|----------|---------| | Project A | 54361 | 54362 | 54363 | 54364 | 54365 | | Project B | 54371 | 54372 | 54373 | 54374 | 54375 | | Project C | 54381 | 54382 | 54383 | 54384 | 54385 |
Generating Unique Ports
When setting up a new project:
- Check existing projects for used port ranges
- Pick a new prefix (e.g., 5438X if 5436X and 5437X are used)
- Configure all services with that prefix
See port-generator.md for a helper.
Setup Workflow
Step 1: Initialize Supabase
cd backend # Supabase lives in backend/
npx supabase init
Step 2: Configure Ports
Edit supabase/config.toml:
[api]
port = 54361
[db]
port = 54362
[studio]
port = 54363
[inbucket]
port = 54364
[storage]
port = 54365
[auth]
port = 54366
[realtime]
port = 54367
See config-template.md for full template.
Step 3: Start Supabase
npx supabase start
Step 4: Get Credentials
npx supabase status
Copy the keys to your .env file.
Migration Workflow
Create Migration
npx supabase migration new descriptive_name
Edit Migration File
Edit supabase/migrations/TIMESTAMP_descriptive_name.sql:
-- Create table
CREATE TABLE public.profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
name TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Enable RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- Create policy
CREATE POLICY "Users can view own profile"
ON public.profiles
FOR SELECT
USING (auth.uid() = user_id);
Apply Migration
npx supabase db push --local
Verify
# Check in Studio
open http://127.0.0.1:PORT # Your Studio port
# Or use psql
PGPASSWORD=postgres psql -h localhost -p PORT -U postgres -d postgres
Type Generation
After schema changes, regenerate TypeScript types:
npx supabase gen types typescript --local > src/database/types.generated.ts
Database Connection Strings
Local Development (direct)
DATABASE_URL=postgresql://postgres:postgres@localhost:PORT/postgres
Docker Development
DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:PORT/postgres
Production (pooler)
DATABASE_URL=postgresql://postgres.PROJECT:PASSWORD@aws-1-region.pooler.supabase.com:5432/postgres
Direct Database Access
For ad-hoc queries, use psql:
# Single command
PGPASSWORD=postgres psql -h localhost -p PORT -U postgres -d postgres -c "SELECT * FROM profiles;"
# Interactive session
PGPASSWORD=postgres psql -h localhost -p PORT -U postgres -d postgres
Common Commands Reference
| Command | Purpose |
|---------|---------|
| npx supabase start | Start local Supabase |
| npx supabase stop | Stop local Supabase |
| npx supabase status | Show credentials and URLs |
| npx supabase migration new NAME | Create new migration |
| npx supabase db push --local | Apply migrations |
| npx supabase gen types typescript --local | Generate types |
| npx supabase db diff | Show schema diff |
Troubleshooting
Port Already in Use
Another Supabase instance is running. Either:
- Stop it:
npx supabase stop - Use different ports in config.toml
Migration Failed
Check the SQL syntax, then:
npx supabase db push --local
If data issues, ask user if they want to reset.
Can't Connect from Docker
Use host.docker.internal instead of localhost:
DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:PORT/postgres
For templates, see config-template.md.