Skip to content
Latchkey

How to Run Database Migrations as a Job Before Deploy in GitHub Actions

Apply a one-shot Job that runs the migration, wait for it with kubectl wait, then roll out the app so new pods never hit an old schema.

Create a Job from the new image that runs the migration command, kubectl wait for its completion, and only then apply the Deployment.

Steps

  • Apply a Job that runs the migration with the new image tag.
  • Wait with kubectl wait --for=condition=complete job/migrate --timeout.
  • Apply or upgrade the Deployment after the Job succeeds.

Workflow

.github/workflows/deploy.yml
steps:
  - run: kubectl apply -f k8s/migrate-job.yaml -n prod
  - run: |
      kubectl wait --for=condition=complete job/migrate \
        -n prod --timeout=300s
  - run: kubectl apply -f k8s/deployment.yaml -n prod

migrate-job.yaml

migrate-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: migrate
spec:
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: ghcr.io/acme/app:latest
          command: ['npm', 'run', 'migrate']

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →