Skip to content

LOCAL SUPABASE SETUP

This guide walks you through setting up a local Supabase instance for development using Docker Compose.

Running Supabase locally provides several benefits:

  • Offline Development: Work without internet connection
  • Cost Savings: No API calls to production during development
  • Data Isolation: Test destructive operations safely
  • Faster Iteration: No network latency
  • Reproducible Environment: Consistent setup across team

Before starting, ensure you have:

  • Docker (v20.10+) and Docker Compose (v2.0+)
  • Make (for convenient commands)
  • At least 4GB RAM available for Docker
  • Ports available: 54321 (API), 54323 (Studio), 5432 (Database)
Terminal window
docker --version # Should be 20.10+
docker-compose --version # Should be 2.0+
make --version # Any recent version
Terminal window
# Copy the environment template
cp .env.local .env.local.custom
# Edit .env.local.custom and update these critical values:
# - POSTGRES_PASSWORD
# - JWT_SECRET
# - ANON_KEY and SERVICE_ROLE_KEY (generate at https://supabase.com/docs/guides/self-hosting)
Terminal window
# Start all Supabase services
make supabase-start
# This will start:
# - PostgreSQL database
# - PostgREST API
# - GoTrue authentication
# - Realtime server
# - Storage server
# - Studio dashboard

Once started, you can access:

Terminal window
# Run all migrations to set up your schema
make supabase-migrate

Update your local environment variables in packages/webapp/.env:

Terminal window
VITE_SUPABASE_URL=http://localhost:54321
VITE_SUPABASE_ANON_KEY=your-anon-key-from-env-local
Terminal window
# In one terminal: keep Supabase running
make supabase-logs
# In another terminal: start your app
make test-watch
# In a third terminal: start the dev server
make dev

The .env.local file contains all configuration for local Supabase. Key variables:

Terminal window
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
POSTGRES_DB=postgres
POSTGRES_PORT=5432
Terminal window
API_EXTERNAL_URL=http://localhost:54321
SUPABASE_PUBLIC_URL=http://localhost:54321
Terminal window
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
JWT_EXPIRY=3600
ANON_KEY=your-anon-key
SERVICE_ROLE_KEY=your-service-role-key
Terminal window
SITE_URL=http://localhost:5173
DISABLE_SIGNUP=false
ENABLE_EMAIL_SIGNUP=true
MAILER_AUTOCONFIRM=true # Auto-confirm emails in dev

To generate proper ANON_KEY and SERVICE_ROLE_KEY:

  1. Visit https://supabase.com/docs/guides/self-hosting/docker#generate-api-keys
  2. Use your JWT_SECRET to generate keys
  3. Or use the default development keys (not for production!)
Terminal window
make supabase-start # Start all services
make supabase-stop # Stop all services
make supabase-restart # Restart all services
make supabase-status # Check service status
make supabase-logs # View service logs (follow mode)
Terminal window
make supabase-db # Connect to database CLI
make supabase-migrate # Run migrations
make supabase-seed # Seed test data
make supabase-backup # Backup database
make supabase-restore FILE=backup.sql # Restore from backup
Terminal window
make supabase-studio # Open Studio in browser
make supabase-reset # Reset database (WARNING: deletes data)
make supabase-clean # Clean up Docker resources

All migrations in supabase/migrations/ are automatically detected:

Terminal window
make supabase-migrate

This runs migrations in alphanumeric order.

  1. Using Studio: Make schema changes in Studio (http://localhost:54323)
  2. Generate SQL: Studio can generate migration SQL
  3. Save Migration: Create file in supabase/migrations/:
    Terminal window
    # Format: YYYYMMDD_description.sql
    touch supabase/migrations/$(date +%Y%m%d)_add_new_table.sql
  4. Apply Migration: Run make supabase-migrate
  • One Change Per Migration: Makes rollback easier
  • Descriptive Names: 20250102_add_user_profiles_table.sql
  • Idempotent SQL: Use IF NOT EXISTS clauses
  • Test Locally First: Always test on local before production

Example migration:

-- supabase/migrations/20250102_add_notifications_table.sql
CREATE TABLE IF NOT EXISTS notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id),
message TEXT NOT NULL,
read BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Enable RLS
ALTER TABLE notifications ENABLE ROW LEVEL SECURITY;
-- Create policies
CREATE POLICY "Users can view own notifications"
ON notifications FOR SELECT
USING (auth.uid() = user_id);

Problem: Docker services fail to start

Solutions:

Terminal window
# Check if ports are already in use
lsof -i :54321 # API port
lsof -i :54323 # Studio port
lsof -i :5432 # Database port
# Stop conflicting services or change ports in .env.local
# Check Docker resources
docker system df
docker system prune -f # Clean up unused resources

Problem: Can’t connect to database

Solutions:

Terminal window
# Check database is running
make supabase-status
# View database logs
docker-compose logs db
# Restart database service
docker-compose restart db

Problem: Studio shows white screen or errors

Solutions:

Terminal window
# Check Studio logs
docker-compose logs studio
# Verify Studio dependencies are healthy
docker-compose ps
# Restart Studio
docker-compose restart studio

Problem: Migration script fails to apply

Solutions:

Terminal window
# Apply migrations one by one to find the issue
for file in supabase/migrations/*.sql; do
echo "Applying: $file"
docker-compose exec -T db psql -U postgres -f - < "$file" || break
done
# Connect to DB and check manually
make supabase-db
# Check for syntax errors in migration files
# Use a SQL linter or Studio's SQL editor

Problem: Slow queries or timeouts

Solutions:

Terminal window
# Increase Docker resources in Docker Desktop settings
# Recommended: 4GB RAM minimum, 8GB preferred
# Check container resource usage
docker stats
# Reset and optimize
make supabase-reset
make supabase-migrate

Problem: Port already in use

Solutions:

Terminal window
# Option 1: Stop conflicting service
sudo lsof -ti:54321 | xargs kill -9
# Option 2: Change ports in .env.local
KONG_HTTP_PORT=44321
STUDIO_PORT=44323
POSTGRES_PORT=44322

Local Supabase consists of multiple services:

┌─────────────────────────────────────────────┐
│ Supabase Studio (54323) │
│ Admin Dashboard & GUI │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Kong Gateway (54321) │
│ API Gateway & Routing │
└─────────────────────────────────────────────┘
│ │ │
┌──────┴───┐ ┌──┴────┐ ┌─┴──────┐
│ │ │ │ │ │
┌───▼───┐ ┌──▼──┐ ┌──▼──┐ ┌────▼────┐
│ REST │ │Auth │ │Real │ │ Storage │
│PostgRE│ │GoTru│ │time │ │ API │
│ ST │ │ e │ │ │ │ │
└───┬───┘ └──┬──┘ └──┬──┘ └────┬────┘
│ │ │ │
└─────────┴────────┴──────────┘
┌──────────▼──────────┐
│ PostgreSQL (5432) │
│ Database + pgvecto│
└─────────────────────┘
  • PostgreSQL: Core database with Supabase extensions
  • PostgREST: Auto-generates REST API from database schema
  • GoTrue: Handles authentication and user management
  • Realtime: WebSocket server for live data subscriptions
  • Storage: Object storage for files and media
  • Kong: API gateway for routing and authentication
  • Studio: Web-based admin dashboard
  • Analytics: Log aggregation with Logflare
  • Vector: Log routing and transformation

Local data is stored in Docker volumes:

docker/volumes/
├── db/data/ # PostgreSQL data files
├── storage/ # Uploaded files and objects
├── api/ # Kong configuration
└── logs/ # Application logs

All services communicate on the supabase-network Docker network:

  • Services use internal hostnames (e.g., db, rest, auth)
  • External access through exposed ports only
  • Kong routes external requests to internal services

Local development differs from production Supabase:

AspectLocalProduction
Auto-confirm emails✅ Enabled❌ Disabled
HTTPS❌ HTTP only✅ Required
Email delivery🔧 Mock/Local✉️ Real SMTP
Backups🔧 Manual☁️ Automated
Resources💻 Limited by Docker☁️ Scalable
Monitoring📊 Basic logs📈 Full observability

For issues with local Supabase setup:

  1. Check Troubleshooting section above
  2. Review Supabase Discord
  3. Open an issue in the project repository
  4. Check Docker logs: make supabase-logs