Automated database migrations on deploy
Resolved 💬 2 comments Opened Jan 25, 2026 by bd28 Closed Feb 12, 2026
Problem
Database migrations are not automatically applied during deployment. When new code that depends on schema changes is deployed, the app crashes because the database schema is out of sync.
Recent incident: Deployed code with run_number column but migration wasn't run, causing production outage.
Requirements
- Migrations must run automatically on every deploy
- Must be idempotent (safe to run multiple times)
- Must fail fast - if migration fails, app shouldn't start
- Must track which migrations have already been applied
- Must run in order (by filename: 0001, 0002, etc.)
- Must work with Docker Compose deployment
- Must be robust for multiple deploys per day
Solution: Startup Migration Runner
1. Migration Tracking Table
CREATE TABLE IF NOT EXISTS schema_migrations (
version VARCHAR(255) PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
2. Migration Runner Script (packages/db/src/migrate.ts)
Node.js script that:
- Connects to PostgreSQL
- Creates
schema_migrationstable if not exists - Reads all
.sqlfiles fromdrizzle/migrations/ - Checks which have already been applied
- Runs pending migrations in order
- Records each successful migration
- Exits with error code if any migration fails
3. Docker Entrypoint
Modify dashboard Dockerfile to use entrypoint script that:
- Runs migration script
- If successful, starts the app
- If migration fails, exits with error (container won't be healthy)
COPY --from=builder /app/packages/db/dist/migrate.js ./migrate.js
COPY --from=builder /app/packages/db/drizzle/migrations ./migrations
ENTRYPOINT ["./entrypoint.sh"]
CMD ["node", "dashboard/server.js"]
entrypoint.sh:
#!/bin/sh
set -e
echo "Running database migrations..."
node migrate.js
echo "Migrations complete, starting app..."
exec "$@"
4. File Structure
packages/db/
├── src/
│ ├── migrate.ts # Migration runner
│ └── ...
├── drizzle/
│ └── migrations/
│ ├── 0001_add_parent_run_fk.sql
│ ├── 0002_pgboss_integration.sql
│ └── ...
└── entrypoint.sh # Docker entrypoint
Implementation Steps
- [ ] Create
schema_migrationstable migration (0000_schema_migrations.sql) - [ ] Create
packages/db/src/migrate.tsscript - [ ] Add build step for migrate.ts in packages/db
- [ ] Create
packages/db/entrypoint.sh - [ ] Update
dashboard/Dockerfileto copy migrations and use entrypoint - [ ] Test locally with Docker Compose
- [ ] Deploy and verify
Testing
- Run
docker compose down -v && docker compose up- should apply all migrations - Run
docker compose restart dashboard- should skip already-applied migrations - Add a new migration file - should apply only the new one on restart
Acceptance Criteria
- [ ] New deployments automatically run pending migrations
- [ ] Already-applied migrations are skipped
- [ ] Failed migrations prevent app from starting
- [ ] Migration status is logged
- [ ] Works with
docker compose up -d --build
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗