diff --git a/docs/docs/cloud-ci-cd/migration-safety-checks.mdx b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx new file mode 100644 index 0000000000000..fa6872add3ae1 --- /dev/null +++ b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx @@ -0,0 +1,138 @@ +--- +description: Add migration safety checks to your Hasura CI/CD pipeline with pgfence +keywords: + - hasura + - docs + - ci-cd + - migrations + - safety + - postgres + - locks + - pgfence +sidebar_label: Migration safety checks +sidebar_position: 50 +--- + +import ProductBadge from '@site/src/components/ProductBadge'; + +# Migration Safety Checks + + + +## Introduction + +When deploying Hasura Migrations to production, certain SQL statements can acquire aggressive Postgres locks that block +reads and writes for the duration of the operation. On large tables, this can cause downtime or cascading lock queue +failures. + +[pgfence](https://pgfence.com) is an open-source CLI that analyzes your migration SQL files **before deployment** and +reports which lock modes each statement acquires, the associated risk level, and safe rewrite alternatives when a +dangerous pattern is detected. + +Adding pgfence to your CI/CD pipeline catches problems like non-concurrent index creation, unsafe column type changes, +and missing `lock_timeout` settings before they reach production. + +## What pgfence detects + +pgfence checks for common Postgres migration footguns, including: + +| Pattern | Risk | Why it's dangerous | +|---------|------|--------------------| +| `CREATE INDEX` (non-concurrent) | Medium | Acquires a `SHARE` lock, blocking all writes | +| `ALTER COLUMN TYPE` | High | Requires `ACCESS EXCLUSIVE` lock and full table rewrite | +| `ADD COLUMN ... NOT NULL` without `DEFAULT` | High | `ACCESS EXCLUSIVE` lock on the entire table | +| `ADD CONSTRAINT ... FOREIGN KEY` (inline) | High | Locks both tables with `ACCESS EXCLUSIVE` | +| `DROP TABLE` / `TRUNCATE` | Critical | `ACCESS EXCLUSIVE` lock, irreversible | +| Missing `SET lock_timeout` | Policy | No timeout means unbounded lock waits | + +For each issue found, pgfence provides the safe alternative — for example, `CREATE INDEX CONCURRENTLY` instead of +`CREATE INDEX`, or the `NOT VALID` + `VALIDATE CONSTRAINT` pattern for foreign keys. + +## Add pgfence to a GitHub Actions workflow + +If you use [GitHub Actions](https://github.com/features/actions) to deploy Hasura Migrations (as recommended for +production in the +[GitHub integration docs](/cloud-ci-cd/github-integration.mdx)), you can add pgfence as a step that runs before +applying migrations. + +### Basic workflow + +Add the following step to your existing workflow file (e.g., `.github/workflows/hasura-deploy.yml`) **before** the step +that applies migrations: + +```yaml +- name: Check migration safety + run: npx --yes @flvmnt/pgfence@0.2.3 analyze --ci hasura/migrations/**/*.sql +``` + +The `--ci` flag causes pgfence to exit with code 1 if any check exceeds the default risk threshold, which will fail the +workflow and prevent the deployment. + +### Full example workflow + +```yaml +name: Hasura Deploy + +on: + push: + branches: [main] + paths: + - 'hasura/migrations/**' + - 'hasura/metadata/**' + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check migration safety + run: npx --yes @flvmnt/pgfence@0.2.3 analyze --ci hasura/migrations/**/*.sql + + - name: Apply migrations + run: hasura migrate apply --endpoint ${{ secrets.HASURA_ENDPOINT }} --admin-secret ${{ secrets.HASURA_ADMIN_SECRET }} + + - name: Apply metadata + run: hasura metadata apply --endpoint ${{ secrets.HASURA_ENDPOINT }} --admin-secret ${{ secrets.HASURA_ADMIN_SECRET }} +``` + +### Controlling the risk threshold + +By default, `--ci` fails the build on `HIGH` risk or above. You can adjust this with `--max-risk`: + +```yaml +- name: Check migration safety + run: npx --yes @flvmnt/pgfence@0.2.3 analyze --ci --max-risk medium hasura/migrations/**/*.sql +``` + +This will fail the build on `MEDIUM` risk or above, catching issues like non-concurrent index creation. + +### JSON output for further processing + +To integrate pgfence results into other tools or dashboards, use the `--output json` flag: + +```yaml +- name: Check migration safety + run: npx --yes @flvmnt/pgfence@0.2.3 analyze --output json hasura/migrations/**/*.sql > pgfence-report.json +``` + +## Adjusting migration paths + +Hasura stores migrations under `hasura/migrations//_/up.sql` by default. Adjust the glob +pattern to match your project structure: + +```yaml +# Single data source named "default" +run: npx --yes @flvmnt/pgfence@0.2.3 analyze --ci hasura/migrations/default/**/up.sql + +# All data sources +run: npx --yes @flvmnt/pgfence@0.2.3 analyze --ci hasura/migrations/**/up.sql +``` + +## Further resources + +- [pgfence documentation](https://pgfence.com) +- [pgfence on npm](https://www.npmjs.com/package/@flvmnt/pgfence) +- [pgfence on GitHub](https://github.com/flvmnt/pgfence) +- [PostgreSQL explicit locking documentation](https://www.postgresql.org/docs/current/explicit-locking.html) +- [Hasura Migrations Best Practices](/migrations-metadata-seeds/migration-best-practices.mdx)