Database Health

CRITICAL RULES

  1. NEVER run drizzle-kit push — it mutates the database directly, bypassing migration files. Always use bunx drizzle-kit generate to create migration SQL, then let the Vercel build step apply it.
  2. NEVER run DDL (ALTER TABLE, DROP, CREATE TABLE) directly against any shared Neon branch.
  3. NEVER edit or reorder files in drizzle/ — the migration journal tracks sequence. If you need to fix a migration, generate a new corrective one.
  4. ALWAYS check which branch you're connected to before any database operation.
  5. For hosted preview, staging, and production, let remote Vercel deploys apply migrations. Do not use local push-style shortcuts.
  6. For direct DB access, use neonctl. Do not copy a raw connection string into ad hoc commands if neonctl can 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

  1. Edit lib/schema.ts
  2. Run ./scripts/db-branch-check.sh — confirm you're NOT on production
  3. Generate migration: bunx drizzle-kit generate
  4. Validate: bun run db:check
  5. Review the generated SQL in drizzle/NNNN_*.sql
  6. Commit the migration files alongside the schema change
  7. Push the branch so Vercel can create/update the preview deployment
  8. Wait for the preview deployment to exist and become usable
  9. Let the remote Vercel build apply migrations to the preview branch database
  10. If you need to discover that preview branch database wiring, run:
  • vercel env pull .env.preview-branch --environment preview --git-branch <branch>
  1. If direct DB access is still needed after that, use neonctl connection-string or neonctl connection-string --psql
  2. Prefer testing the live preview URL over local database-only validation
  3. 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_URLpooled (via pgbouncer). Use for runtime queries. Cannot run DDL.
  • DATABASE_URL_UNPOOLEDdirect. 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:

  1. Push the branch.
  2. Wait for the Vercel preview deployment to exist and become usable.
  3. Test the live preview URL first.
  4. Only if you need to discover branch DB wiring after that, use vercel env pull --environment preview --git-branch <branch>.
  5. 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.

If You're Lost