fix(migrations): prevent migrations from opening their own connections - #1215
Merged
RUKAYAT-CODER merged 1 commit intoAug 21, 2026
Conversation
rinafcode#1211) All migrations run inside one shared transaction (TypeORM default "all" mode), so a migration that opens its own pooled connection cannot see uncommitted tables/rows created by earlier migrations in the same run and its changes escape atomic rollback. This was the root cause of the fix-invoice-number-sequence failure from scratch (rinafcode#1195). Document the constraint in the migrations README and the database migration guide, and add a CI guard (scripts/validate-migrations.js) that fails the build if any migration calls createQueryRunner() or touches queryRunner.connection. Audited all 29 existing migrations: none open their own connection. Generated with Codebuff 🤖 Co-Authored-By: Codebuff <noreply@codebuff.com>
Contributor
|
Thank you for contributing to the project |
Contributor
Author
Always. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1211
Summary
TypeORM's default
migrationsTransactionModeisall— every migration in a run executes inside a single shared transaction. A migration that opens its own connection (viaqueryRunner.connection.createQueryRunner()ordataSource.createQueryRunner()) gets a separate pooled connection that:relation "X" does not existon any fresh database (this was exactly thefix-invoice-number-sequencefailure resolved in fix(migrations): add baseline schema so migration:run works from scratch #1195);This PR documents the constraint and enforces it in CI so the footgun cannot silently return.
Changes
src/migrations/README.md— rewritten to describe the actual TypeORM migration system and document the single-transaction rule with a Do / Don't example.docs/migrations.md— new "Transaction behavior (important)" section and a best-practices row.scripts/validate-migrations.js(new) — CI guard that scans every migration file forcreateQueryRunner()/ direct.connectionaccess and fails the build when found..github/workflows/ci.yml— newmigrations:checkstep in the validate job (runs beforemigration:run).package.json— addsmigrations:checkscript and includes the guard inpnpm run verify.Audit
All 29 migration files were audited: none open their own connection — every migration uses only the
QueryRunnerpassed toup()/down().Test evidence
The guard was also validated against a planted violation (
queryRunner.connection.createQueryRunner()in a migration): it correctly fails with a line-level error message identifying the offending file and line.The validate job also runs
migration:run,migration:generate:check(drift), andmigration:revertagainst Postgres 16 — these will run on this PR.