Preview Environments

Configure staging environments with Vercel preview deployments and separate Supabase projects.

This guide documents our cost-effective preview environment setup using:

  • Local Docker Supabase - For development and initial testing
  • Separate Free-Tier Supabase Project - For staging (development branch)
  • Production Supabase Project - For main branch
  • Vercel Preview Deployments - Automatic deployments per branch

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         WORKFLOW                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   LOCAL                    STAGING                 PRODUCTION    │
│   ─────                    ───────                 ──────────    │
│                                                                  │
│   feature/xyz      →      development       →      main          │
│        │                       │                     │           │
│        ▼                       ▼                     ▼           │
│   Docker Supabase      Free-Tier Project       Pro Project       │
│   (pnpm dev)           (Vercel Preview)        (Vercel Prod)     │
│                                                                  │
│   Cost: $0                Cost: $0              Cost: $25/mo     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Cost Summary

EnvironmentDatabaseCost
LocalDocker Supabase$0
Staging (development)Free-tier Supabase project$0
Production (main)Pro Supabase project$25/month
Total$25/month

Prerequisites

  • Supabase Pro Plan for production
  • Vercel account with project connected
  • GitHub repository
  • Separate free-tier Supabase project for staging

Phase 1: Create Staging Supabase Project

1.1 Create New Free-Tier Project

  1. Go to Supabase Dashboard
  2. Click New Project
  3. Configure:
    • Name: eminentid-staging (or similar)
    • Database Password: Generate a strong password (save it!)
    • Region: Same as production for consistency
    • Plan: Free tier
  4. Click Create new project

1.2 Get Staging Credentials

Once the project is created, go to SettingsAPI and note:

  • Project URL (e.g., https://xxxxx.supabase.co)
  • anon/public key
  • service_role key (keep secret!)

1.3 Apply Migrations to Staging

You need to apply your existing migrations to the staging database.

Important: Run all Supabase CLI commands from the apps/web directory where the supabase/ folder with migrations lives:

# Navigate to apps/web first
cd apps/web

# Link to the staging project
npx supabase link --project-ref <staging-project-ref>

# Push migrations
npx supabase db push

Alternatively, you can run migrations via the Supabase Dashboard SQL editor.


Phase 2: Configure Vercel Environment Variables

2.1 Set Up Branch-Specific Environment Variables

  1. Go to Vercel DashboardYour ProjectSettingsEnvironment Variables

  2. Add staging credentials for the development branch:

    VariableValueEnvironment
    NEXT_PUBLIC_SUPABASE_URLhttps://[staging-ref].supabase.coPreview
    NEXT_PUBLIC_SUPABASE_ANON_KEY[staging-anon-key]Preview
    SUPABASE_SERVICE_ROLE_KEY[staging-service-role-key]Preview
  3. Important: When adding each variable, click "Add to specific branches" and enter development

    This ensures only the development branch uses staging credentials. Other preview branches will use production (or you can set different values).

2.2 Verify Production Variables

Ensure your production variables are set for the Production environment:

VariableValueEnvironment
NEXT_PUBLIC_SUPABASE_URLhttps://[prod-ref].supabase.coProduction
NEXT_PUBLIC_SUPABASE_ANON_KEY[prod-anon-key]Production
SUPABASE_SERVICE_ROLE_KEY[prod-service-role-key]Production

Phase 3: Set Up Git Branches

3.1 Create Development Branch

The development branch already exists. Verify it:

git fetch origin
git checkout development

3.2 Verify Vercel Deployments

After pushing to development, Vercel should deploy to:

  • Staging URL: [project]-git-development-[team].vercel.app

Check that this deployment uses the staging Supabase credentials.


Phase 4: Enforce the Development Flow (GitHub Action)

Prevent anyone from merging feature branches directly to main. All code must flow through development first.

Note: GitHub Rulesets and Branch Protection rules require GitHub Team ($4/user/month) for private repos. We use a GitHub Action as a free alternative.

How It Works

A GitHub Action (.github/workflows/enforce-development-flow.yml) runs on every PR to main and fails if the source branch is not development.

name: Enforce Development Flow

on:
  pull_request:
    branches: [main]

jobs:
  check-source-branch:
    runs-on: ubuntu-latest
    steps:
      - name: Check if PR is from development branch
        run: |
          if [[ "${{ github.head_ref }}" != "development" ]]; then
            echo "❌ PRs to main must come from the 'development' branch."
            exit 1
          fi
          echo "✅ PR is from development branch. Allowed."

What This Enforces

ActionResult
feature/xyzdevelopmentAllowed
developmentmainAllowed
feature/xyzmainCheck fails (soft block)

Limitations

This is a soft block - the check fails but anyone with merge access can still override and merge. For hard enforcement, upgrade to GitHub Team.

Upgrading to GitHub Team (Future)

When you upgrade, you can use proper branch protection:

  1. Go to SettingsBranchesAdd branch protection rule
  2. Branch name pattern: main
  3. Enable Require status checks to pass before merging
  4. Add check-source-branch as a required check
  5. Enable Do not allow bypassing the above settings

Phase 5: The Workflow

Daily Development Flow

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   LOCAL      │     │   STAGING    │     │  PRODUCTION  │
│              │     │              │     │              │
│ feature/xyz  │ ──► │ development  │ ──► │    main      │
│              │     │              │     │              │
│ Docker DB    │     │ Free-tier DB │     │   Pro DB     │
│ localhost    │     │ Vercel URL   │     │  Prod URL    │
└──────────────┘     └──────────────┘     └──────────────┘
     TEST                 TEST                DEPLOY

Step-by-Step

  1. Create feature branch from development

    git checkout development
    git pull origin development
    git checkout -b feature/my-feature
    
  2. Develop locally

    pnpm supabase:web:start   # Start local Docker Supabase
    pnpm dev                   # Start Next.js dev server
    
    • Make your code changes
    • Test with local database
  3. Schema changes (if needed)

    pnpm --filter web supabase migrations new my_schema_change
    # Edit the generated SQL file in apps/web/supabase/migrations/
    
  4. Push and create PR to development

    git add .
    git commit -m "feat: my feature"
    git push origin feature/my-feature
    
    • Open PR targeting development branch (not main!)
  5. Test on staging

    • Merge PR into development
    • Apply migrations to staging DB (from apps/web directory):
      cd apps/web
      npx supabase link --project-ref <staging-project-ref>
      npx supabase db push
      
    • Test on staging URL: [project]-git-development.vercel.app
    • Verify everything works with real (staging) data
  6. Promote to production

    • Create PR: developmentmain
    • Apply migrations to production DB (from apps/web directory):
      cd apps/web
      npx supabase link --project-ref <prod-project-ref>
      npx supabase db push
      
    • Merge PR
    • Vercel deploys to production

Phase 6: Keeping Databases in Sync

Running Migrations

Since we're using separate Supabase projects (not branching), you need to manually apply migrations to each environment.

Local:

pnpm supabase:web:reset  # Resets and applies all migrations

Staging:

cd apps/web
npx supabase link --project-ref <staging-project-ref>
npx supabase db push

Production:

cd apps/web
npx supabase link --project-ref <prod-project-ref>
npx supabase db push

Seed Data (Staging Only)

Create a seed file for staging test data at apps/web/supabase/seed.sql:

-- Seed data for staging environment
-- This file should be idempotent (safe to run multiple times)

-- Example: Insert test organization
INSERT INTO public.accounts (id, name, slug, is_personal_account)
VALUES
  ('00000000-0000-0000-0000-000000000001', 'Test Organization', 'test-org', false)
ON CONFLICT (id) DO NOTHING;

-- Add more seed data as needed...

Apply seed data:

npx supabase db reset --linked  # WARNING: This wipes the database first
# OR
psql <staging-connection-string> -f apps/web/supabase/seed.sql

Configuration Checklist

Environment Variables

Ensure these are never hardcoded - always use process.env:

  • NEXT_PUBLIC_SUPABASE_URL
  • NEXT_PUBLIC_SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY

Security

  • Row Level Security (RLS) policies are active on all tables
  • RLS policies applied to both staging and production
  • Staging credentials are NOT production credentials

Git Ignore

Ensure these are in .gitignore:

  • .env.local
  • .env*.local
  • Any files containing secrets

Troubleshooting

Staging URL shows production data

  1. Check Vercel environment variables for development branch
  2. Verify variables are scoped to "Preview" and specific to development branch
  3. Redeploy the development branch

Migrations out of sync

  1. Check migration files in apps/web/supabase/migrations/
  2. Run npx supabase db push on the target environment
  3. If conflicts, check the supabase_migrations table in the database

Can't merge to main

  1. Verify you're merging from development branch
  2. Check GitHub ruleset is configured correctly
  3. If emergency, use a hotfix/* branch (if exception is configured)

Free tier project paused

Free-tier Supabase projects pause after 1 week of inactivity. To prevent:

  1. Set up a cron job or GitHub Action to ping the database weekly
  2. Or simply unpause manually when needed for testing

Quick Reference

URLs

EnvironmentVercel URLSupabase Dashboard
Productionyour-domain.comProduction Project
Stagingproject-git-development.vercel.appStaging Project
Locallocalhost:3000localhost:54323

Commands

# Local development
pnpm supabase:web:start      # Start local Supabase
pnpm dev                      # Start Next.js

# Migrations (run from apps/web directory)
cd apps/web
pnpm --filter web supabase migrations new <name>  # Create migration
npx supabase db push                               # Apply to linked project

# Switch between projects (run from apps/web directory)
cd apps/web
npx supabase link --project-ref <ref>              # Link to a project

References