8. Migrate from Supabase to Neon Database
Date: 2025-10-24
Status
Proposed
Context
During our production database migration to Supabase, the database became inaccessible during a backup restoration operation. After five days of support engagement, the database remains unavailable and backups appear to have been accidentally deleted. Fortunately, this occurred before we started using the production database, so no customers or revenue were affected.
This incident revealed a critical concern:
- Backup Vulnerability: Backups can be accidentally deleted by support or operations
Decision
Migrate from Supabase to Neon serverless PostgreSQL before production deployment.
Why Neon:
- Immutable Backups: 30-day point-in-time recovery that cannot be accidentally deleted
- Serverless-First: Built for Vercel/Next.js with fast cold starts (<100ms) and automatic scaling
- Database Branching: Git-like workflow for safe testing of schema changes
- 100% PostgreSQL Compatible: All custom functions, RLS policies, and indexes work identically
Migration Approach:
- Apply the existing schema to Neon
- Copy the only used tables: cargos_states and cargos_citizenship
- Minimal code changes (Prisma already abstracts database layer)
Alternatives Considered:
- Stay with Supabase: Reliability concerns remain; as of this ADR’s creation, the production account is still inaccessible
- AWS RDS: Higher cost ($400-800/month), operational overhead, poor serverless fit
- PlanetScale: Their PostgreSQL service was just launched and is quite limited. For example, it’s not available in all regions and their PGBouncer doesn’t support replicas; all queries are sent to the main server.
- Self-hosted: Unacceptable operational burden
Consequences
Benefits
- Improved Reliability: Multi-AZ storage with immutable backups prevents accidental data loss
- Better Architecture: Serverless-native design optimized for our Vercel deployment
- Developer Productivity: Database branching enables safe testing of migrations
Risks & Mitigations
- Data Loss During Migration: Maintain Supabase for 7 days post-cutover
- Custom Functions: Recreate snowflake_id() function and test thoroughly in staging
- RLS Policies: Document and recreate all 3 RLS policies before cutover
- Performance: Load test staging with production-like traffic before migration
Migration Tasks
- Set up Neon staging database and apply Prisma schema
- Configure logical replication from Supabase to Neon
- Test all custom functions and RLS policies
- Update connection strings and deploy to production
- Monitor for 48 hours post-cutover; keep Supabase running for 7 days as safety net