Database Health
CRITICAL RULES
- NEVER run
drizzle-kit push— it mutates the database directly, bypassing migration files. Always usebunx drizzle-kit generateto create migration SQL, then let the Vercel build step apply it. - NEVER run DDL (
ALTER TABLE,DROP,CREATE TABLE) directly against any shared Neon branch. - NEVER edit or reorder files in
drizzle/— the migration journal tracks sequence. If you need to fix a migration, generate a new corrective one. - ALWAYS check which branch you're connected to before any database operation.
- For hosted preview,
staging, and production, let remote Vercel deploys apply migrations. Do not use local push-style shortcuts. - For direct DB access, use
neonctl. Do not copy a raw connection string into ad hoc commands ifneonctlcan provide the access path.
Quick Health Check
Run the full health check:
./scripts/db-health.sh
This validates: connection string, Neon branch, drizzle-kit check, migration journal integrity, and table count.
Branch Check
Before any database work, confirm your target:
./scripts/db-branch-check.sh
This script will fail with exit code 1 if you're connected to production (Neon main branch) unless you pass --allow-production.
Schema Change Workflow
- Edit
lib/schema.ts - Run
./scripts/db-branch-check.sh— confirm you're NOT on production - Generate migration:
bunx drizzle-kit generate - Validate:
bun run db:check - Review the generated SQL in
drizzle/NNNN_*.sql - Commit the migration files alongside the schema change
- Push the branch so Vercel can create/update the preview deployment
- Wait for the preview deployment to exist and become usable
- Let the remote Vercel build apply migrations to the preview branch database
- If you need to discover that preview branch database wiring, run:
vercel env pull .env.preview-branch --environment preview --git-branch <branch>
- If direct DB access is still needed after that, use
neonctl connection-stringorneonctl connection-string --psql - Prefer testing the live preview URL over local database-only validation
- Run full health check only when local database health is the actual question
Never apply hosted preview, staging, or production migrations manually. The Vercel build step runs migrations automatically using DATABASE_URL_UNPOOLED (direct connection, not pooled).
Pooled vs Unpooled URLs
DATABASE_URL— pooled (via pgbouncer). Use for runtime queries. Cannot run DDL.DATABASE_URL_UNPOOLED— direct. Used by Drizzle migrations at build time. Required for DDL.
Both must point at the same Neon branch.
The Staging-as-Default Quirk
The Neon-Vercel integration uses the Neon default branch for production. We set staging as default so preview branches fork from staging data. This means the integration sets Production DATABASE_URL to the wrong endpoint. Production DATABASE_URL must be set manually. See ENVIRONMENT.md for the full matrix.
Preview Branch Testing
When validating a feature branch:
- Push the branch.
- Wait for the Vercel preview deployment to exist and become usable.
- Test the live preview URL first.
- Only if you need to discover branch DB wiring after that, use
vercel env pull --environment preview --git-branch <branch>. - If you still need direct DB access, use
neonctl.
The preview deployment is the most production-like environment for branch validation. Prefer that over local shortcuts.