Skip to content

ci(migrations): skip db:migrate on merges that change no migration files#5225

Closed
waleedlatif1 wants to merge 1 commit into
stagingfrom
ci-migrate-investigate
Closed

ci(migrations): skip db:migrate on merges that change no migration files#5225
waleedlatif1 wants to merge 1 commit into
stagingfrom
ci-migrate-investigate

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Every push to main/staging ran db:migrate against the production/staging database even when the merge changed no schema. A no-op migration still opens a connection and takes the advisory lock, so it fails any time the DB is at its connection limit — 53300: remaining connection slots are reserved for roles with the SUPERUSER attribute — red-X'ing UI-only merges (e.g. a recent docs/component-only merge to staging).

This adds a path-based gate so the apply step runs only when migration files actually changed.

Changes

  • ci.yml: new detect-migrations job (dorny/paths-filter on packages/db/migrations/**, mirroring the existing check-docs-changes job). Its output is passed into the reusable migrations workflow.
  • migrations.yml: new migrations_changed input; the versioned-apply step is skipped when it is 'false'.

Why it's safe (no deploy breakage, no skipped migrations)

  • The migrate job still runs on every push to main/staging, so downstream jobs that need: [migrate] (the image build/deploy) are never skipped. Only the DB-touching step is gated.
  • The flag defaults to 'true' and only ever skips on a literal 'false'. Manual workflow_dispatch (no input) and any unknown/empty value therefore always apply migrations — the gate can only skip a provably-empty change, never a real one.
  • dev (db:push) path is unchanged.

Best practice

Path-filtering migration jobs so they run only when migration files change is a widely recommended CI/CD pattern; the universal requirement both schools of thought agree on is idempotency (apply only pending migrations), which this repo's migrate.ts already satisfies. Sources in the PR thread.

Follow-up (separate, infra)

The underlying failure is connection-slot exhaustion: the non-superuser migration role can't use superuser_reserved_connections. Real migrations can still hit this under load — worth giving the migration path dedicated/reserved capacity. Not addressed here.

Type of Change

  • CI / infrastructure

Testing

  • Both workflows parse; job graph verified (migrate still gates the build via needs). Behavior is exercised on the next push to staging.

Checklist

Every push to main/staging ran db:migrate against the production/staging
database even when the merge changed no schema, so a no-op migration would dial
the DB and fail whenever it was at its connection limit (53300, slots reserved
for SUPERUSER) — red-X'ing UI-only merges.

Add a detect-migrations job (dorny/paths-filter on packages/db/migrations/**)
and pass the result into the reusable migrations workflow, which now skips the
apply step when no migration files changed. The migrate job still runs so
downstream build/deploy jobs that need it are never skipped, and the flag
defaults to 'true' so manual dispatch and any unknown value always apply
migrations — the gate only ever skips a provably-empty change.
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 26, 2026 6:50pm

Request Review

@cursor

cursor Bot commented Jun 26, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
CI-only gating with fail-safe default 'true'; deploy ordering unchanged because migrate still runs. Residual risk is a path-filter false negative skipping a needed migrate—mitigated by only skipping on explicit 'false'.

Overview
Stops no-op db:migrate runs on main/staging pushes that don’t touch schema, so UI-only merges no longer open production/staging DB connections (and fail when the pool is exhausted).

ci.yml adds a detect-migrations job using dorny/paths-filter on packages/db/migrations/** (same pattern as check-docs-changes). The migrate job still runs every push and still gates build-amd64 via needs; it now depends on detect-migrations and passes migrations_changed into the reusable workflow.

migrations.yml accepts optional migrations_changed (default 'true'). For production/staging, when the flag is exactly 'false', the apply step logs and skips migrate.ts; dev db:push is unchanged. Manual dispatch and missing inputs still migrate.

Reviewed by Cursor Bugbot for commit 358a957. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a CI gate for production and staging migrations. The main changes are:

  • A new detect-migrations job checks packages/db/migrations/** on main and staging pushes.
  • The main/staging migrate job passes that result into the reusable migrations workflow.
  • The reusable workflow skips db:migrate only when the input is exactly 'false'.
  • The dev db:push path stays unchanged.

Confidence Score: 5/5

This looks safe to merge after considering the deploy-path hardening note.

  • The migration skip path is conservative and only skips on a literal false value.
  • Empty or omitted values still run migrations.
  • The new dependency can make a paths-filter failure block deployment, but that is an infrastructure hardening issue rather than an incorrect migration skip.

.github/workflows/ci.yml

Important Files Changed

Filename Overview
.github/workflows/ci.yml Adds migration path detection and wires it into the main/staging migration job before the build/deploy chain.
.github/workflows/migrations.yml Adds an optional migrations_changed input and keeps migration execution as the default unless the value is exactly 'false'.

Reviews (1): Last reviewed commit: "ci(migrations): skip db:migrate on merge..." | Re-trigger Greptile

Comment thread .github/workflows/ci.yml
migrate:
name: Migrate DB
needs: [test-build]
needs: [test-build, detect-migrations]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Filter Failure Blocks Deploys

When detect-migrations fails before producing an output, the new needs edge cancels migrate, and build-amd64 cannot run because it needs migrate. That makes a checkout or paths-filter infrastructure failure block the whole main/staging deploy path, even though the safe fallback should be to run migrations rather than skip the deploy.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Closing in favor of addressing the root cause — connection-slot capacity / the migration role not being able to use reserved slots — rather than gating migrations in CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant