How to Run Database Migrations Before Deploy in GitHub Actions
Shipping code that expects a new schema before the migration ran is a recipe for downtime; migrate first, then deploy.
Run migrations in a dedicated job that the deploy needs:, so a failed migration blocks the deploy entirely.
Steps
- Put migrations in their own job with the database connection as a secret.
- Make the deploy job
needs:the migrate job. - Use forward-compatible (expand/contract) migrations so old and new code coexist.
- Fail loudly so a broken migration stops the deploy.
Workflow
.github/workflows/deploy.yml
jobs:
migrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: ./migrate.sh up
deploy:
needs: migrate
runs-on: ubuntu-latest
steps:
- run: ./deploy.shGotchas
- Use expand/contract migrations so the currently running code does not break mid-deploy.
- Make migrations idempotent so a retried job does not double-apply.
- Latchkey runs migration jobs on cheaper runners that retry transient connection failures before the deploy.
Related guides
How to Gate Deploy on a Successful Staging Deploy in GitHub ActionsBlock a production deploy in GitHub Actions until staging deploys successfully, using job dependencies and a…
How to Set Up a Postgres + Redis Service for Tests in GitHub ActionsRun Postgres and Redis as service containers in a GitHub Actions job with health checks, so integration tests…