CtrlK
BlogDocsLog inGet started
Tessl Logo

nitinjain999/platform-skills

Production-grade platform engineering handbook — Kubernetes, Terraform, Flux CD, GitHub Actions, AWS, and more.

67

Quality

84%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

README.mdexamples/github-actions/composite-actions/db-migrate/

db-migrate

Run database migrations safely with health check, advisory lock, verification, and automatic summary. Supports Flyway, Liquibase, and golang-migrate.

Status: Stable

Quick start

- uses: your-org/actions/db-migrate@v1
  with:
    database_url: ${{ secrets.DATABASE_URL }}
    migration_dir: migrations/

How it works

inputs.database_url (masked immediately)
        │
        ▼
Validate inputs + mask secret
        │
        ▼
Health check — nc -z host:port (10 retries × 3s)
        │
        ▼
Install migration tool (flyway | liquibase | golang-migrate)
        │
        ▼
dry_run=true  → print pending migrations → stop
dry_run=false → acquire advisory lock → migrate up → release lock
        │
        ▼
verify_after=true → validate schema version
        │
        ▼
outputs.migrations_applied   (count of files applied)
outputs.current_version      (schema version after migration)
Job summary (always)

Inputs

InputTypeRequiredSecretDefaultDescription
database_urlstringYesYesFull connection URL — pass ${{ secrets.DATABASE_URL }}
migration_toolchoiceNoNogolang-migrateflyway / liquibase / golang-migrate
migration_dirstringNoNomigrationsDirectory containing migration files
flyway_versionstringNoNo10.10.0Flyway version (when migration_tool=flyway)
liquibase_versionstringNoNo4.27.0Liquibase version (when migration_tool=liquibase)
golang_migrate_versionstringNoNov4.17.1golang-migrate version
dry_runbooleanNoNofalsePrint pending migrations without applying
verify_afterbooleanNoNotrueRun post-migration schema verification
lock_timeout_secondsstringNoNo60Seconds to wait for migration lock

Outputs

OutputDescription
migrations_appliedNumber of migration files applied
current_versionSchema version after migration
dry_run_outputPending migrations list (dry_run=true only)

Variables and secrets

# What is a secret:
# database_url — contains credentials (user:password@host) — MUST come from secrets store

# What is safe to log:
# migration_tool, migration_dir, dry_run, verify_after, versions — no credentials

The database_url is masked with ::add-mask:: in the first line of the first step. If it leaks in any tool output, it will be redacted.

- uses: your-org/actions/db-migrate@v1
  with:
    database_url: ${{ secrets.DATABASE_URL }}       # secret
    migration_tool: golang-migrate                  # safe to hardcode
    migration_dir: db/migrations                    # safe to hardcode

Logged in job summary: tool, directory, dry-run flag, migrations applied, schema version. Never logged: the database URL or any credential extracted from it.


Permissions

permissions:
  contents: read   # checkout only — no GitHub API calls

No id-token: write needed unless your database uses IAM authentication (pass the IAM token in the URL).


Idempotency

Idempotent — all supported tools track applied migrations in a schema version table (schema_migrations, flyway_schema_history, or DATABASECHANGELOG). Re-running applies only pending migrations. Running with no pending migrations is a no-op.


Concurrency — prevent parallel migration runs

Parallel migrations on the same database can corrupt schema state. Use a GitHub Actions concurrency group keyed on the database environment:

concurrency:
  group: db-migrate-${{ inputs.environment }}
  cancel-in-progress: false   # never cancel a migration in progress

Full example — deploy pipeline with pre-migration dry run

name: Deploy

on:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  # Step 1 — dry run on PR to show what will change
  preview-migrations:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Preview pending migrations
        id: preview
        uses: your-org/actions/db-migrate@v1
        with:
          database_url: ${{ secrets.STAGING_DATABASE_URL }}
          migration_dir: db/migrations
          dry_run: 'true'

      - name: Post migration preview as PR comment
        uses: your-org/actions/pr-comment@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          title: 'Pending database migrations'
          body: |
            ```
            ${{ steps.preview.outputs.dry_run_output }}
            ```

  # Step 2 — apply on merge to main
  migrate-and-deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    concurrency:
      group: db-migrate-production
      cancel-in-progress: false
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

      - name: Run database migrations
        id: migrate
        uses: your-org/actions/db-migrate@v1
        with:
          database_url: ${{ secrets.PRODUCTION_DATABASE_URL }}
          migration_dir: db/migrations
          migration_tool: golang-migrate
          verify_after: 'true'
          lock_timeout_seconds: '120'

      - name: Deploy application
        run: |
          echo "Schema at version ${{ steps.migrate.outputs.current_version }}"
          echo "Applied ${{ steps.migrate.outputs.migrations_applied }} migrations"
          # ... deploy app after migrations succeed

Rollback guidance

This action does not perform automatic rollback — migration rollback is inherently data-destructive and must be a deliberate choice.

For safe rollback:

# golang-migrate — roll back N steps
migrate -path db/migrations -database "$DATABASE_URL" down 1

# Flyway — undo the last applied migration (requires Flyway Teams or Enterprise)
flyway -url="$DATABASE_URL" undo

# Liquibase — roll back to a tagged version
liquibase rollback --tag=v1.2.3

Write reversible migrations where possible (add columns before removing old ones, create new tables before dropping old ones).


Changelog

See CHANGELOG.md

examples

BEFORE_AFTER.md

CHANGELOG.md

CODE_OF_CONDUCT.md

COMMANDS.md

CONTRIBUTING.md

EDITOR_INTEGRATIONS.md

GETTING_STARTED.md

HOW_IT_WORKS.md

install.sh

INSTALLATION.md

LAUNCH.md

PROMPTS.md

QUICKSTART.md

README.md

renovate.json

SECURITY.md

SKILL.md

tessl.json

tile.json