1. Why Schema Drift Causes Outages
Database schema drift occurs when an environment’s actual schema catalog diverges from the expected state defined in your application codebase. Common culprits include:
- Emergency Hotfixes: An engineer adds an index or alters a column directly on production during an incident and forgets to backport the change into migration scripts.
- Out-of-Order Branch Merges: Two feature branches branch off main, apply conflicting DDL, and get deployed in reverse order.
- Manual DBA Maintenance: Index rebuilds, vacuum tweaks, or table partition adjustments that were not documented in source control.
When your next deployment pipeline runs, application ORMs (like Prisma, Drizzle, Hibernate, or ActiveRecord) attempt to run migrations against unexpected column structures, resulting in failed transactions, locked tables, and customer downtime.
2. Deterministic Exit Codes in dbmt
The dbmt CLI is engineered specifically for non-interactive scripting. Every command returns standard POSIX exit codes so your CI runners can make clear pass/fail decisions:
Exit Code 0 : Clean parity. Schemas are identical (in sync).Exit Code 1 : Drift detected! Schema differences found between source and target.Exit Code 2 : Connection error. Database unreachable, bad credentials, or SSL failure.Exit Code 3 : Safety gate violation. Target schema modified during execution or unconfirmed drop.Interactive CI/CD Workflow Builder
Adapt these templates for a prepared macOS runner with dbmt installed and an approved same-engine comparison profile. Review flags, exit behavior, credentials, and trigger rules for your installed version.
name: Database Schema Drift Gate
on:
pull_request:
branches: [main]
paths:
- 'migrations/**'
- 'schema/**'
jobs:
verify-schema:
runs-on: [self-hosted, macOS]
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Check prepared dbmt installation
run: dbmt --version
- name: Check Schema Drift Against Staging
env:
DBMIGRATE_MASTER_KEY: ${{ secrets.DBMIGRATE_MASTER_KEY }}
TARGET_DB_URL: ${{ secrets.STAGING_DATABASE_URL }}
run: |
# Configure branch protection and command exit behavior for your workflow
dbmt compare --profile staging-sync3. GitHub Actions Integration
Start with a manually triggered workflow on a prepared macOS runner. Configure your approved profile and review the installed command behavior before adding pull-request or deployment triggers:
name: Database Schema Review
on:
workflow_dispatch:
jobs:
compare:
# Prepare dbmt, database access, and an approved profile on this runner.
runs-on: [self-hosted, macOS]
steps:
- name: Check installed version
run: dbmt --version
- name: Compare the approved profile
run: dbmt compare --profile ci-staging-check
4. GitLab CI Pipeline Example
Use a prepared macOS shell runner tagged macos and dbmt. Adapt the profile, credentials, and job policy before adding this example to .gitlab-ci.yml:
stages: [database-review]
schema_review:
stage: database-review
tags: [macos, dbmt]
# Prepare dbmt, database access, and the comparison profile on this runner.
script:
- dbmt --version
- dbmt compare --profile ci-staging-check
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
5. Automated PR Commenting
When dbmt compare catches differences, you can automatically post the planned synchronization DDL as a comment on the pull request. This lets database administrators and tech leads review the exact ALTER TABLE and CREATE INDEX statements before approving the PR.
6. Production Protection Controls
Even in headless CI environments, dbmt respects connection protection profiles:
- Pre-Apply Snapshot: On high-protection targets,
dbmt applyautomatically takes a schema snapshot before executing DDL. - Destructive Statement Gates: If a sync plan contains
DROP TABLEorDROP COLUMN, execution requires the explicit flag--allow-destructiveto prevent accidental data loss. - Re-Check Target Parity: Immediately before running the first SQL statement,
dbmtre-checks the target schema catalog. If another transaction changed the database, execution aborts with exit code 3.