Gate a PR in CI

On GitHub, start with the official DBLift Action (uses: dblift/action@v1). It installs the pip package and runs migrate, validate, or info. Other runners stay pip install plus a DBLift command.

On GitHub, start with the official DBLift Action (uses: dblift/action@v1). It installs the pip package and runs migrate, validate, or info. Other runners stay pip install plus a DBLift command.

The Action does not start a database. Every command needs a reachable one — these recipes supply an ephemeral Postgres service and pass the connection through DBLIFT_DB_URL.

oss · migrate · validate · info

GitHub Actions

dblift/actioncommand is migrate, validate, or info (ignored when args is set). args is raw CLI passthrough and overrides command. extras defaults to postgresql. Python defaults to 3.11.

.github/workflows/dblift.yml

name: Database migrations
on: pull_request

jobs:
  migrate:
    runs-on: ubuntu-latest
    env:
      DBLIFT_DB_URL: postgresql+psycopg://dblift:dblift@localhost:5432/dblift
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: dblift
          POSTGRES_PASSWORD: dblift
          POSTGRES_DB: dblift
        ports:
          - 5432:5432
        options: >-
          --health-cmd "pg_isready -U dblift -d dblift"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v5
      - uses: dblift/action@v1
        with:
          command: migrate
          extras: postgresql

Applying the migrations to the ephemeral Postgres service above is the check: dblift's migrate validates before it applies, so a bad checksum or a broken ordering fails the job rather than being written to the database.

Set pr-comment: true to post the pending migration plan as a pull request comment. That needs permissions: pull-requests: write on the workflow or job. On fork PRs the token is read-only, so the Action falls back to the job's step summary. The plan is rendered before the command runs, so command: migrate with pr-comment: true comments the pending set at job start, then applies it. args suppresses the pr-comment plan render.

sql is populated only when pr-comment: true and args is empty. pending-count is empty when args is set or the pending probe fails. Reading exit-code from a later step requires continue-on-error: true on the Action step; otherwise a non-zero dblift status fails the job immediately and later steps never see the output.

Validate on pull requests that touch migrations

on:
  pull_request:
    paths:
      - 'migrations/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    env:
      DBLIFT_DB_URL: postgresql+psycopg://dblift:dblift@localhost:5432/dblift
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: dblift
          POSTGRES_PASSWORD: dblift
          POSTGRES_DB: dblift
        ports:
          - 5432:5432
        options: >-
          --health-cmd "pg_isready -U dblift -d dblift"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v5
      - uses: dblift/action@v1
        with:
          command: validate

validate still needs a reachable database. The Action does not start one.

Without the Action

Pip-install on the runner when you are not using the Action:

name: dblift
on:
  pull_request:
    paths: ["migrations/**"]

jobs:
  validate:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: dblift
          POSTGRES_PASSWORD: dblift
          POSTGRES_DB: dblift
        ports: ["5432:5432"]
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    env:
      DBLIFT_DB_URL: postgresql+psycopg://dblift:dblift@localhost:5432/dblift
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
          cache: pip
      - run: pip install "dblift[postgresql]"
      - run: dblift migrate
      - run: dblift validate
      - run: dblift info

GitLab CI

.gitlab-ci.yml

stages: [validate]

validate-migrations:
  stage: validate
  image: python:3.11
  services:
    - name: postgres:16
      alias: postgres
  variables:
    POSTGRES_USER: dblift
    POSTGRES_PASSWORD: dblift
    POSTGRES_DB: dblift
    DBLIFT_DB_URL: "postgresql+psycopg://dblift:dblift@postgres:5432/dblift"
  rules:
    - changes: [migrations/**/*]
  script:
    - pip install "dblift[postgresql]"
    - dblift migrate
    - dblift validate
    - dblift info

[!NOTE] One config, many stages

Rather than exporting a different DBLIFT_DB_URL per stage, declare the stages once under environments: in dblift.yaml and select with --env, DBLIFT_ENV, or a branch mapping under resolve.branch_map.

Pre-commit

.pre-commit-config.yaml

repos:
  - repo: https://github.com/dblift/dblift
    rev: v3.8.0   # pin to a released tag
    hooks:
      - id: dblift-validate
        additional_dependencies: ["dblift[postgresql]"]
      - id: dblift-info
        additional_dependencies: ["dblift[postgresql]"]

Because the hooks use language: python, pre-commit builds an isolated environment holding only the base package. Name the driver extra in additional_dependencies for the database you connect to, or the hook will have no driver. The same applies to pre-commit try-repo, locally and in CI.

[!NOTE] No database-free lint in OSS

The hooks need a configured dblift.yaml or DBLIFT_DB_URL and a reachable database — typically the local dev database from your docker-compose.yml. Offline SQL linting is validate-sql, which is Pro.

DBLift is information technology / developer tools software. Contact: contact@dblift.com.