From df6fae1e69df04dd06a311edf69367ee5ca5fbcc Mon Sep 17 00:00:00 2001 From: Munteanu Flavius-Ioan Date: Thu, 26 Feb 2026 00:58:12 +0200 Subject: [PATCH 1/3] docs: add pgfence migration safety check to CI/CD workflow Add a new page under Cloud CI/CD docs showing how to integrate pgfence as a pre-deployment migration safety check in GitHub Actions workflows. pgfence analyzes Hasura migration SQL files for dangerous Postgres lock patterns (non-concurrent indexes, unsafe ALTER COLUMN, missing lock_timeout) and fails the CI build before risky migrations reach production. --- .../cloud-ci-cd/migration-safety-checks.mdx | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 docs/docs/cloud-ci-cd/migration-safety-checks.mdx 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..9c28d753402de --- /dev/null +++ b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx @@ -0,0 +1,134 @@ +--- +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 +--- + +# 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.dev) 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 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 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 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 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 analyze --ci hasura/migrations/default/**/up.sql + +# All data sources +run: npx --yes @flvmnt/pgfence analyze --ci hasura/migrations/**/up.sql +``` + +## Further resources + +- [pgfence documentation](https://pgfence.dev) +- [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) From 20093041c7f565728b8691698a80f1833ae87e75 Mon Sep 17 00:00:00 2001 From: Munteanu Flavius-Ioan Date: Thu, 26 Feb 2026 01:26:58 +0200 Subject: [PATCH 2/3] fix: add ProductBadge, pin pgfence version, remove hidden unicode chars --- .../docs/cloud-ci-cd/migration-safety-checks.mdx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/docs/cloud-ci-cd/migration-safety-checks.mdx b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx index 9c28d753402de..22685ff245147 100644 --- a/docs/docs/cloud-ci-cd/migration-safety-checks.mdx +++ b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx @@ -13,8 +13,12 @@ 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 @@ -58,7 +62,7 @@ that applies migrations: ```yaml - name: Check migration safety - run: npx --yes @flvmnt/pgfence analyze --ci hasura/migrations/**/*.sql + run: npx --yes @flvmnt/pgfence@0.2.1 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 @@ -83,7 +87,7 @@ jobs: - uses: actions/checkout@v4 - name: Check migration safety - run: npx --yes @flvmnt/pgfence analyze --ci hasura/migrations/**/*.sql + run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci hasura/migrations/**/*.sql - name: Apply migrations run: hasura migrate apply --endpoint ${{ secrets.HASURA_ENDPOINT }} --admin-secret ${{ secrets.HASURA_ADMIN_SECRET }} @@ -98,7 +102,7 @@ By default, `--ci` fails the build on `HIGH` risk or above. You can adjust this ```yaml - name: Check migration safety - run: npx --yes @flvmnt/pgfence analyze --ci --max-risk medium hasura/migrations/**/*.sql + run: npx --yes @flvmnt/pgfence@0.2.1 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. @@ -109,7 +113,7 @@ To integrate pgfence results into other tools or dashboards, use the `--output j ```yaml - name: Check migration safety - run: npx --yes @flvmnt/pgfence analyze --output json hasura/migrations/**/*.sql > pgfence-report.json + run: npx --yes @flvmnt/pgfence@0.2.1 analyze --output json hasura/migrations/**/*.sql > pgfence-report.json ``` ## Adjusting migration paths @@ -119,10 +123,10 @@ pattern to match your project structure: ```yaml # Single data source named "default" -run: npx --yes @flvmnt/pgfence analyze --ci hasura/migrations/default/**/up.sql +run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci hasura/migrations/default/**/up.sql # All data sources -run: npx --yes @flvmnt/pgfence analyze --ci hasura/migrations/**/up.sql +run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci hasura/migrations/**/up.sql ``` ## Further resources From e1be41ee626ea2ec05c5654825f44fa027ea36ab Mon Sep 17 00:00:00 2001 From: Munteanu Flavius-Ioan <145166224+flvmnt@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:33:54 +0200 Subject: [PATCH 3/3] fix: use pgfence.com domain, update to v0.2.3 --- .../docs/cloud-ci-cd/migration-safety-checks.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/docs/cloud-ci-cd/migration-safety-checks.mdx b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx index 22685ff245147..fa6872add3ae1 100644 --- a/docs/docs/cloud-ci-cd/migration-safety-checks.mdx +++ b/docs/docs/cloud-ci-cd/migration-safety-checks.mdx @@ -25,7 +25,7 @@ When deploying Hasura Migrations to production, certain SQL statements can acqui reads and writes for the duration of the operation. On large tables, this can cause downtime or cascading lock queue failures. -[pgfence](https://pgfence.dev) is an open-source CLI that analyzes your migration SQL files **before deployment** and +[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. @@ -62,7 +62,7 @@ that applies migrations: ```yaml - name: Check migration safety - run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci hasura/migrations/**/*.sql + 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 @@ -87,7 +87,7 @@ jobs: - uses: actions/checkout@v4 - name: Check migration safety - run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci hasura/migrations/**/*.sql + 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 }} @@ -102,7 +102,7 @@ By default, `--ci` fails the build on `HIGH` risk or above. You can adjust this ```yaml - name: Check migration safety - run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci --max-risk medium hasura/migrations/**/*.sql + 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. @@ -113,7 +113,7 @@ To integrate pgfence results into other tools or dashboards, use the `--output j ```yaml - name: Check migration safety - run: npx --yes @flvmnt/pgfence@0.2.1 analyze --output json hasura/migrations/**/*.sql > pgfence-report.json + run: npx --yes @flvmnt/pgfence@0.2.3 analyze --output json hasura/migrations/**/*.sql > pgfence-report.json ``` ## Adjusting migration paths @@ -123,15 +123,15 @@ pattern to match your project structure: ```yaml # Single data source named "default" -run: npx --yes @flvmnt/pgfence@0.2.1 analyze --ci hasura/migrations/default/**/up.sql +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.1 analyze --ci hasura/migrations/**/up.sql +run: npx --yes @flvmnt/pgfence@0.2.3 analyze --ci hasura/migrations/**/up.sql ``` ## Further resources -- [pgfence documentation](https://pgfence.dev) +- [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)