Source:
ocean/docs/adr/0053-schema-drift-prevention.md| ✏️ Edit on GitHub
ADR-053: Schema Drift Prevention Strategy
Status
Accepted
Context
We discovered significant schema drift between local and production databases:
- Migrations were applied directly to production without version control
- Column names differed (
errorvserror_message) - Missing columns in various tables
- Constraint mismatches
- Function permission issues
This caused "Database error saving new user" for all new signups.
Decision
1. Comprehensive Migration Applied
Created migration 20250903100000_fix_schema_drift_comprehensive.sql that:
- Fixes all column naming inconsistencies
- Adds missing columns with proper defaults
- Ensures nullable constraints are correct
- Updates functions with proper permissions
- Creates verification functions
2. Prevention Mechanisms
Automated Schema Verification
- Script:
scripts/verify-schema.ts- Runs health checks on schema - Script:
scripts/detect-schema-drift.ts- Compares environments - Commands:
pnpm schema:verify- Verify schema healthpnpm schema:detect-drift- Detect differences
CI/CD Integration
- Workflow:
.github/workflows/schema-verification.yml- Runs on every PR with migration changes
- Verifies migrations apply cleanly
- Tests user creation flow
- Generates schema snapshots on main branch
Git Hooks
- Pre-push hook: Automatically verifies schema when migrations change
- Prevents pushing broken migrations
- Ensures local testing before deployment
3. Migration Best Practices
Naming Convention
YYYYMMDDHHMMSS_descriptive_name.sql
Example: 20250903100000_fix_schema_drift_comprehensive.sql
Migration Structure
-- Always use IF EXISTS checks
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'table_name'
AND column_name = 'column_name'
) THEN
ALTER TABLE public.table_name ADD COLUMN column_name TYPE;
END IF;
END $$;
Testing Requirements
- Apply locally first:
pnpm supabase migration up --local - Run verification:
pnpm schema:verify - Test critical flows (user creation)
- Only then push to repository
4. Production Deployment Process
-
Never apply migrations directly to production
-
Always commit to version control first
-
Follow deployment flow:
Local → Git → CI/CD → Staging → Production
5. Recovery Procedures
If drift is detected:
- Run
pnpm schema:detect-driftto identify differences - Create a comprehensive fix migration
- Test thoroughly in local environment
- Deploy through normal channels
Consequences
Positive
- No more schema drift between environments
- Automated detection of issues
- Clear audit trail of all schema changes
- Safer deployments with verification
Negative
- Slightly slower push process when migrations change
- Requires local Supabase for development
- More rigid deployment process
Trade-offs
- We prioritize consistency over deployment speed
- Automation reduces human error
- Early detection prevents production issues
Implementation Status
✅ Comprehensive migration applied ✅ Verification scripts created ✅ CI/CD workflow implemented ✅ Pre-push hooks updated ✅ Local environment fixed and working ✅ Commands added to package.json
Lessons Learned
- Schema drift is silent but deadly - It only shows up when users try to sign up
- Version control everything - Including migrations
- Automate verification - Humans forget to check
- Test the critical path - User signup must always work
- Use idempotent migrations - IF EXISTS prevents double-application