Version: 2.2.1 Last Updated: 2026-04-24 Based on: Supabase Official Documentation This guide provides recommendations for configuringDocumentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
supabase/config.toml to support four environments:
- Local - Local CLI development (Docker)
- Dev - Persistent dev project (
zkgxozahyczcnzpwhbbf); per-PR preview DBs created by Branching from PRs targeting GitHubprod - Staging (Persistent) - UAT and pre-prod validation
- Production - Live application (
srcaoozjkrughebmbvfb); per-PR preview DBs created by Branching only for release PRs targeting GitHubproduction
Authoritative branch ↔ Vercel ↔ Supabase mapping: see
VERCEL_SUPABASE_ENV_ALIGNMENT.md.
When that document and this one disagree, the alignment doc wins.
2026-04 reconcile: the legacy production project (zkgxozahyczcnzpwhbbf)
was repurposed as Dev. Two new clean projects were created from a single
optimized baseline migration. See
SUPABASE_RECONCILE_2026-04.md for the
cutover record.
As of 2026-04-22 — source of truth and deploy path
- Dev (
zkgxozahyczcnzpwhbbf, “Encore OS”): Lovable + Supabase MCP apply migrations and deploy Edge Functions here first; this database is the live schema reference for day-to-day work. - Git repo (
supabase/migrations/,supabase/functions/): canonical history for review and for production rollout. - Production (
srcaoozjkrughebmbvfb, “encore_os_prod”): Supabase Branching (GitHub integration) replays migrations for release PRs and, with Deploy to production ON, applies them on merge toproduction. CI still runssupabase db push --yesfrom.github/workflows/supabase-deploy-prod.ymlon the same push as a reconcile with the repo. Break-glass: manualworkflow_dispatchon that workflow withskip_db_pushwhen migrations were already fully applied elsewhere (document in your ops log).
db push at Dev for schema promotion; treat Dev as MCP-driven. Use GitHub prod → optional .github/workflows/supabase-deploy-dev.yml backstop, and production → prod.
Bidirectional sync (Dev ↔ repo)
Two paths keep Dev and the repo aligned:- Repo → Dev (push): Author routine DDL declaratively under
supabase/schemas/, then runnpm run db:schemas:diff -- -f <slug>(wrapssupabase stop+supabase db diff -f <slug>) to emit the migration insupabase/migrations/. Reservesupabase migration newfor caveat migrations (DML, certainALTER POLICY/ view ownership / grant / comment cases — see DECLARATIVE_SCHEMA_GUIDE.md and MIGRATION_LANES.md). The migrations land on the Dev project whensupabase-deploy-dev.ymlruns on its branch trigger (see workflow table below). - Dev → repo (pull): Migrations applied directly to Dev by Lovable / Supabase MCP are captured back into
supabase/migrations/bysupabase-sync-from-dev.yml. It runs daily at 06:00 UTC and on-demand viaworkflow_dispatch. The workflow runssupabase db diff --linked -f <slug>to produce a real timestamped migration, validates it withdb reset+ the RLS / FK / lane guards, refreshes the declarative tree undersupabase/schemas/vianpm run db:schemas:exportwhen bootstrapped (so the repo’s source of truth stays current), regeneratessrc/integrations/supabase/types.ts, and opens a review PR todev. Developers can run the same flow locally withnpm run db:pull-from-dev -- --name <slug>.
Promotion path
prod → production): Require green Supabase Preview on encore_os_prod before merge. Order of operations and branch protection are documented in VERCEL_SUPABASE_ENV_ALIGNMENT.md section 2.3. CLI spike notes: BRANCHING_CI_SPIKE.md.
Optional persistent staging (separate Supabase project) can sit between Dev and Prod when provisioned; there is no shared staging ref in config.toml until you add one.
Recommended Configuration Structure
Option 1: Remote-Specific Configuration (RECOMMENDED)
This approach uses Supabase’s[remotes] configuration blocks to define environment-specific settings. This is the recommended approach per Supabase documentation.
Option 2: Environment Variable-Based (Alternative)
If you prefer to switch environments via environment variables:.env files:
.env.local→SUPABASE_PROJECT_ID=local-dev.env.staging→SUPABASE_PROJECT_ID=<staging-ref>.env.production→SUPABASE_PROJECT_ID=srcaoozjkrughebmbvfb
Workflow by Environment
Local Development
Purpose: Feature development, migration testing, rapid iteration Setup:[api], [db] settings in config.toml
Staging (Persistent UAT)
Purpose: User acceptance testing, integration testing, pre-production validation Setup:[remotes.staging] block from config.toml
Best Practices:
- Keep staging schema in sync with production
- Use synthetic test data (no PHI/PII)
- Test all migrations in staging before production
- Use staging for UAT sign-offs
Production
Purpose: Live application serving real users Canonical mapping: GitHub branchproduction, project ref srcaoozjkrughebmbvfb — see VERCEL_SUPABASE_ENV_ALIGNMENT.md.
Setup:
[remotes.production] block from config.toml
Best Practices:
- NEVER deploy untested migrations to production
- Always deploy to staging first
- Use production for verified, tested changes only
- Monitor deployments closely
- Have rollback plan ready
Environment Switching Workflow
Recommended: Use Separate Git Branches
Alternative: Manual Linking
Configuration Options Reference
API Configuration
Database Configuration
Remote-Specific Overrides
Secrets Management
Local Development
Secrets are loaded from.env file in project root:
config.toml:
Remote Environments (Staging/Production)
Set secrets via CLI:Migration Workflow
Recommended Flow
CI/CD Integration
For automated deployments, use GitHub Actions with environment-specific secrets:Best Practices
1. Always Test Locally First
- Use
supabase db resetto test migrations from scratch - Verify migrations are idempotent (can be run multiple times safely)
2. Staging Before Production
- NEVER deploy directly to production
- Always validate in staging first
- Use staging for UAT sign-offs
3. Environment Isolation
- Keep production and staging completely separate
- Never use production data in staging
- Use synthetic test data in staging
4. Configuration as Code
- Keep
config.tomlin version control - Use
[remotes]blocks for environment-specific settings - Document any manual configuration changes
5. Secrets Management
- Never commit secrets to git
- Use
.envfiles for local development (gitignored) - Use
supabase secrets setfor remote environments - Rotate secrets regularly
6. Migration Safety
- Always review migrations before deploying
- Test rollback procedures
- Use transactions where possible
- Avoid breaking changes when possible
Troubleshooting
Issue: Wrong Project Linked
Symptom:supabase db push deploys to wrong environment
Solution:
Issue: Config Not Applied
Symptom: Remote-specific config not taking effect Solution:- Verify
project_idin[remotes.*]matches actual project ID - Use
supabase config pushto sync config to remote - Check that you’re linked to correct project
Issue: Secrets Not Available
Symptom: Edge functions can’t access secrets Solution:Migration from Current Setup
Current State
config.tomlhas singleproject_id = "<STAGING_PROJECT_REF>"(staging)- Manual switching between environments
Recommended Migration Steps
-
Backup current config:
-
Update config.toml:
- Add default local configuration
- Add
[remotes.production]block - Add
[remotes.staging]block - Keep current staging project_id
-
Test local development:
-
Test staging link:
-
Test production link:
-
Update documentation:
- Update
docs/development/ENVIRONMENT_CONFIG.mdwith new workflow - Document switching process for team
- Update
Database connections for scripts (pooler, not direct)
Supabase’s direct Postgres hostname (db.<project-ref>.supabase.co) is often IPv6-only. Many local networks and CI runners only resolve IPv4, which surfaces as ENOTFOUND or connection timeouts when using pg, psql, or pg_dump.
Use the Session pooler for any script that opens a raw Postgres connection from a laptop or CI:
- Dashboard → Project Settings → Database → Connection string → Session mode (Supavisor, port 5432).
- URI shape:
postgresql://postgres.<PROJECT_REF>:<PASSWORD>@aws-0-<REGION>.pooler.supabase.com:5432/postgres
SUPABASE_DEV_DB_URL— dev (zkgxozahyczcnzpwhbbf), pooler URI.SUPABASE_PROD_DB_URL— prod (srcaoozjkrughebmbvfb), pooler URI.
.env.local only (gitignored). See .env.local.example.
Applying the global system-defaults bundle to prod
- Regenerate
supabase/seeds/system-defaults/00_global_system_defaults.sql(npm run seed:extract-system-defaultsor--source rest). - Prefer recording the load in migration history: in Cursor, use the Supabase MCP
apply_migrationtool againstsrcaoozjkrughebmbvfbwith migration nameseed_global_system_defaults_bundleandqueryset to the file contents (same SQL as the SQL Editor path). - Fallback: paste the file into the prod project SQL Editor and run.
- Fresh production project (empty / first-time): run the manual GitHub Actions workflow Bootstrap Supabase (production) (see workflow table below). It runs
supabase db push --include-all, thensupabase db query --linked --fileon00_global_system_defaults.sql, then optionalnpm run check:prod-seed-paritywhenSUPABASE_PROD_DB_URLis configured as a secret.
Migration lanes (schema vs system data)
New migrations must follow the lane rules in MIGRATION_LANES.md so CI can block dev-only URLs, JWTs in SQL, and non-idempotent catalog inserts after the strict cutoff timestamp.Ongoing parity check
npm run check:prod-seed-parity compares prod catalog row counts to dev (if SUPABASE_DEV_DB_URL is set) or to documented minimum baselines. It skips when SUPABASE_PROD_DB_URL is unset (e.g. CI without secrets). Set that variable in CI to enforce the gate in automation.
GitHub Actions (Supabase deploy + drift)
Workflows live under.github/workflows/:
| Workflow | Trigger | Action |
|---|---|---|
supabase-deploy-prod.yml | Push to production touching supabase/migrations/**, supabase/functions/**, or supabase/config.toml | supabase link → srcaoozjkrughebmbvfb → post-link migration audit → db push --yes → deploy changed Edge Functions only (or all if _shared / config / unknown before SHA) |
supabase-bootstrap-prod.yml | Manual workflow_dispatch with confirm bootstrap-new-prod | db push --include-all → db query --linked system-defaults bundle → optional seed parity |
supabase-deploy-dev.yml | Push to prod with same path filters (or manual) | supabase link → soft drift check (auto-dispatches supabase-sync-from-dev.yml if drift exists; bypass via force_deploy_dev) → db push --yes → selective function deploy |
supabase-sync-from-dev.yml | Daily 06:00 UTC + manual workflow_dispatch with migration_name | supabase db diff --linked -f <slug> → validates with db reset + RLS / FK / lane guards → regenerates src/integrations/supabase/types.ts → opens PR to dev with the captured migration |
supabase-promote-pr.yml | PR → production when migrations (or lane script) change | Migration lane report + sticky PR comment |
db-migration-guard.yml | PR → main or production when migrations change | RLS init-plan + FK index checks; migration lane on main PRs only |
build.yml | PR → main, production, or feature/** | Full app CI gate |
| Secret | Used by |
|---|---|
SUPABASE_ACCESS_TOKEN | Supabase CLI auth (deploy, drift, bootstrap) |
SUPABASE_PROD_DB_PASSWORD | supabase-deploy-prod.yml, supabase-bootstrap-prod.yml (supabase link --password) |
SUPABASE_DEV_DB_PASSWORD | supabase-deploy-dev.yml, supabase-drift-check.yml |
SUPABASE_PROD_DB_URL (optional) | supabase-bootstrap-prod.yml seed parity step |
db diff --linked requires Docker on the runner; if the drift job logs a CLI/Docker failure, fix runner setup or run the diff locally.
References
- Supabase Configuration Documentation
- Managing Environments Guide
- Local Development Guide
- CLI Config Reference
Summary
Recommended Approach: Use[remotes] configuration blocks in config.toml to define environment-specific settings. This provides:
✅ Clear separation between environments✅ Environment-specific configuration overrides
✅ Version-controlled configuration
✅ Easy switching via
supabase link✅ Support for different settings per environment Workflow:
- Local:
supabase start(uses default config), thensupabase db resetwhen testing migrations. - Dev (Encore OS):
zkgxozahyczcnzpwhbbf— primary schema changes via Lovable + MCP; optional GitHubprodbranch workflow mirrors repo → Dev. - Production (
encore_os_prod):srcaoozjkrughebmbvfb— promote via GitHubproductionbranch (CI) or manualsupabase link+db push+functions deployfollowing SUPABASE_RECONCILE_2026-04.md.