ankane/strong_migrations
Catch unsafe migrations in development
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2w ago
- ✓3 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Small team — 3 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 98% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ankane/strong_migrations)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/ankane/strong_migrations on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ankane/strong_migrations
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ankane/strong_migrations shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 2w ago
- 3 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Small team — 3 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 98% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ankane/strong_migrations
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ankane/strong_migrations.
What it runs against: a local clone of ankane/strong_migrations — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ankane/strong_migrations | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 44 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ankane/strong_migrations. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ankane/strong_migrations.git
# cd strong_migrations
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ankane/strong_migrations and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ankane/strong_migrations(\\.git)?\\b" \\
&& ok "origin remote is ankane/strong_migrations" \\
|| miss "origin remote is not ankane/strong_migrations (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "lib/strong_migrations.rb" \\
&& ok "lib/strong_migrations.rb" \\
|| miss "missing critical file: lib/strong_migrations.rb"
test -f "lib/strong_migrations/checker.rb" \\
&& ok "lib/strong_migrations/checker.rb" \\
|| miss "missing critical file: lib/strong_migrations/checker.rb"
test -f "lib/strong_migrations/checks.rb" \\
&& ok "lib/strong_migrations/checks.rb" \\
|| miss "missing critical file: lib/strong_migrations/checks.rb"
test -f "lib/strong_migrations/migration.rb" \\
&& ok "lib/strong_migrations/migration.rb" \\
|| miss "missing critical file: lib/strong_migrations/migration.rb"
test -f "lib/strong_migrations/adapters/abstract_adapter.rb" \\
&& ok "lib/strong_migrations/adapters/abstract_adapter.rb" \\
|| miss "missing critical file: lib/strong_migrations/adapters/abstract_adapter.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 44 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~14d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ankane/strong_migrations"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Strong Migrations is a Rails gem that catches unsafe database migration operations during development before they run in production. It analyzes migrations for operations that could block reads/writes or cause runtime errors (like removing columns, changing column types, adding foreign keys without CONCURRENTLY on Postgres), blocks them by default, and provides clear instructions for safer alternatives. It supports PostgreSQL, MySQL, and MariaDB. Monolithic gem structure: lib/strong_migrations/ contains the core checker engine (checker.rb, checks.rb), database adapters for each platform (adapters/), and a Rails integration layer (railtie.rb, migration.rb). The lib/generators/ provides Rails generators for installation. Tests live alongside in test/ with one test file per check type.
👥Who it's for
Ruby on Rails developers writing database migrations who want to prevent dangerous operations from accidentally reaching production; database administrators and DevOps engineers who need safety guardrails around schema changes.
🌱Maturity & risk
Production-ready and actively maintained. The project is battle-tested at Instacart, has comprehensive test coverage across 40+ test files in test/, CI/CD via GitHub Actions (build.yml), and supports multiple Rails versions (7.2, 8.0, 8.2 gemfiles). Clear indication of ongoing maintenance and stability.
Low risk for active deployments. Single maintainer (ankane) is a known Rails community contributor, but dependency on Rails versions requires keeping in sync. No indication of deprecated dependencies or major breaking changes in CHANGELOG. Risk is minimal if Rails version stays current.
Active areas of work
The repo appears actively maintained with support for newest Rails versions (8.2 gemfile added). The CHANGELOG and test suite suggest continuous addition of new checks and database-specific safeguards. Specific recent work likely includes maintaining compatibility with Rails 8.x and expanding Postgres/MySQL/MariaDB-specific checks.
🚀Get running
git clone https://github.com/ankane/strong_migrations.git
cd strong_migrations
bundle install
bundle exec rake test
Daily commands:
bundle exec rake test # Run full test suite
bundle exec rake test:sqlite # Or specific DB tests
bundle exec rails generate strong_migrations:install # Install in a Rails app
🗺️Map of the codebase
lib/strong_migrations.rb— Main entry point that initializes the gem and integrates with Railslib/strong_migrations/checker.rb— Core validation engine that checks migrations for unsafe operationslib/strong_migrations/checks.rb— Defines all safety checks for dangerous migration patterns (removing columns, adding constraints, etc.)lib/strong_migrations/migration.rb— Patches ActiveRecord::Migration to intercept and validate migration operationslib/strong_migrations/adapters/abstract_adapter.rb— Base adapter class that defines the interface for database-specific safety checkslib/strong_migrations/error_messages.rb— Provides user-friendly error messages and remediation guidance for unsafe operationslib/strong_migrations/railtie.rb— Rails integration point that registers the migration checker with Rails lifecycle
🧩Components & responsibilities
- Checker (Ruby, ActiveRecord introspection) — Orchestrates all safety checks, determining if a migration is safe to execute
- Failure mode: False positives (blocking safe migrations) or false negatives (allowing unsafe migrations). Detected via test suite.
- Database Adapters (PostgreSQL/MySQL/MariaDB-specific SQL knowledge) — Implement database-specific safety rules and constraints, translating generic checks to database-specific behavior
- Failure mode: Database-specific unsafe operations not detected. Each adapter needs comprehensive test coverage.
- Migration Hook (Rails Railtie, ActiveRecord monkey-patching) — Intercepts ActiveRecord migration execution and routes through safety checker before allowing execution
- Failure mode: Hook fails to intercept migration (e.g., due to monkey-patch conflicts), allowing unsafe migrations to run undetected
- Error Messages (Ruby string formatting) — Provides human-readable error messages and actionable remediation guidance
- Failure mode: Unclear or incorrect guidance leads developers to implement unsafe workarounds
🔀Data flow
Rails Migration Runner→Migration Hook— Migration execution event is intercepted by the Railtie hookMigration Hook→Checker— Migration object and context passed to Checker for validationChecker→undefined— undefined
🛠️How to make changes
Add a New Safety Check
- Define the check logic in
lib/strong_migrations/checks.rbby adding a new method to the Checks class (lib/strong_migrations/checks.rb) - Call the new check method from the main validation method in
lib/strong_migrations/checker.rb(lib/strong_migrations/checker.rb) - Define error message and remediation guidance in
lib/strong_migrations/error_messages.rb(lib/strong_migrations/error_messages.rb) - Add database-specific overrides if needed in the appropriate adapter file (e.g.,
lib/strong_migrations/adapters/postgresql_adapter.rb) (lib/strong_migrations/adapters/abstract_adapter.rb) - Create comprehensive test cases in a new test file like
test/new_check_test.rb(test/add_column_test.rb)
Support a New Database
- Create a new adapter class inheriting from
AbstractAdapterinlib/strong_migrations/adapters/new_database_adapter.rb(lib/strong_migrations/adapters/abstract_adapter.rb) - Override database-specific check methods to handle unique constraints and syntax (
lib/strong_migrations/adapters/postgresql_adapter.rb) - Register the new adapter in the initialization logic in
lib/strong_migrations.rb(lib/strong_migrations.rb) - Add gemfile for the new database version in
gemfiles/and update CI workflow in.github/workflows/build.yml(gemfiles/activerecord72.gemfile)
Add a Safe Method Override
- Add the migration method signature to the safe methods whitelist in
lib/strong_migrations/safe_methods.rb(lib/strong_migrations/safe_methods.rb) - Document the override in the initializer template so users understand when to use it (
lib/generators/strong_migrations/templates/initializer.rb.tt) - Add test cases in
test/safe_by_default_test.rbto verify the override works correctly (test/safe_by_default_test.rb)
🔧Why these technologies
- Ruby on Rails — Gem is designed specifically for Rails applications and integrates at the framework level via Railtie
- ActiveRecord — Patches ActiveRecord::Migration to intercept and validate all database migration operations
- Database Adapters (PostgreSQL, MySQL, MariaDB) — Each database has different locking and performance characteristics, requiring adapter pattern for database-specific safety rules
⚖️Trade-offs already made
-
Development-only enforcement by default
- Why: Prevents false positives and deployment friction in production while catching issues early
- Consequence: Requires explicit configuration to enforce safety in production; developers must use
SKIP_STRONG_MIGRATIONSif they've validated the risk
-
Blocking migrations instead of auto-fixing
- Why: Database migrations are high-risk operations that require human judgment; automatic fixes could mask problems or cause data loss
- Consequence: Developers must understand and explicitly approve the safe approach, increasing development time but improving safety
-
Adapter pattern for database-specific logic
- Why: Different databases have different locking semantics, index creation costs, and constraint mechanisms
- Consequence: Increased code complexity, but enables accurate safety checks that match each database's actual behavior
-
Statement timeout override during migrations
- Why: Large table migrations can be expensive and might hit app-level statement timeouts, causing rollbacks
- Consequence: Requires separate timeout configuration for migrations vs. application code, slightly increased operational complexity
🚫Non-goals (don't propose these)
- Does not automatically fix or refactor unsafe migrations
- Does not enforce style or schema design patterns beyond safety
- Does not provide migration scheduling or zero-downtime deployment orchestration
- Does not monitor or track production migration execution
- Does not support databases outside PostgreSQL, MySQL, and MariaDB
🪤Traps & gotchas
- The gem hooks into ActiveRecord's migration system via monkey-patching
Migrationclass; this requires the gem to be loaded before migrations run, which is handled by Railtie but must be kept in the Gemfile (not Gemfile.lock only). 2. Database adapter selection is automatic based on the connection's database type, but custom adapters or connection pooling setups may bypass detection. 3. Thesafety_assured { }block disables checks entirely for that operation—use sparingly and ensure the surrounding code handles the unsafe operation correctly. 4. Tests require activerecord gems to be installed; running tests without matching gemfile (e.g.,bundle exec rake testwithout specifying activerecord version) may cause mismatches.
🏗️Architecture
💡Concepts to learn
- Table locks and lock wait timeouts — Strong Migrations classifies operations as unsafe based on how long they hold table locks; understanding lock acquisition is critical to deciding which operations to
safety_assured - Non-concurrent index creation (CONCURRENTLY) — PostgreSQL-specific check that enforces
CONCURRENTLYkeyword for adding indexes on live tables; this is a key safety pattern the gem validates - ActiveRecord column caching — Strong Migrations detects column removal as dangerous because Rails caches column definitions; understanding this caching behavior explains why the gem enforces
ignored_columnspattern - Volatile vs. immutable default values — PostgreSQL-specific check that flags defaults like
NOW()as unsafe because they execute at different times; requires understanding SQL function immutability - Algorithm selection in MySQL ALTER TABLE (COPY vs. INPLACE) — MySQL/MariaDB-specific check that validates which algorithm is safe; COPY algorithm blocks reads/writes while INPLACE may use different locking
- Foreign key constraint cascading — Strong Migrations requires explicit choice of
dependent: :deleteor similar when adding foreign keys to prevent silent data loss and constraint violations - Check constraints and domain constraints — The gem tracks constraints added to columns to prevent narrowing existing value ranges, which would invalidate existing rows and block migrations
🔗Related repos
rails/rails— Strong Migrations is built on ActiveRecord's migration framework; understanding Rails' migration internals is essential contextseanlynch/zero-downtime-migrations— Similar gem for PostgreSQL zero-downtime migrations; competitive alternative with overlapping safety checksbrandur/sql-playground— Educational resource on database locking and migration safety patterns that inform Strong Migrations' checksankane/pghero— Companion gem from same maintainer for PostgreSQL monitoring; often used alongside Strong Migrations to catch perf issues earlythoughtbot/scenic— Rails gem for managing database views; complements Strong Migrations by providing safe patterns for schema changes
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive tests for MariaDB adapter edge cases
The repo supports PostgreSQL, MySQL, and MariaDB, but the test suite lacks MariaDB-specific test coverage. Currently, test files like add_column_test.rb, change_column_null_test.rb, etc. don't have dedicated MariaDB variants. This would ensure database-specific safety checks work correctly across all supported databases.
- [ ] Review lib/strong_migrations/adapters/mariadb_adapter.rb to identify MariaDB-specific behavior
- [ ] Create test/support/mariadb_helper.rb with MariaDB test database configuration
- [ ] Add MariaDB-specific test cases to test/add_column_test.rb for constraint handling differences
- [ ] Add MariaDB-specific test cases to test/change_column_null_test.rb for NULL constraint behavior
- [ ] Run full test suite against MariaDB to validate
Add integration tests for multiple database scenario validation
The repo has test/multiple_databases_test.rb but it appears minimal. Given that strong_migrations must work across PostgreSQL, MySQL, and MariaDB simultaneously in production environments, we need comprehensive tests validating that unsafe migrations are caught consistently across all adapters for the same scenario.
- [ ] Expand test/multiple_databases_test.rb with test cases for each unsafe pattern (add_column without default, removing columns, adding constraints, etc.)
- [ ] Create parametrized tests that run the same migration against all three database adapters
- [ ] Add assertions validating error messages are consistent across adapters
- [ ] Test safe_by_default behavior with all database combinations
Add tests for safe_methods.rb custom allowlist validation
The lib/strong_migrations/safe_methods.rb file allows users to customize what's considered safe, but there are no dedicated tests validating this configuration works correctly. Contributors should add tests for the custom allowlist feature that verify users can properly disable specific checks.
- [ ] Review lib/strong_migrations/safe_methods.rb to understand the allowlist mechanism
- [ ] Create test/safe_methods_customization_test.rb with tests for adding custom safe methods
- [ ] Add tests validating that disabled checks are actually skipped during migration runs
- [ ] Add tests for edge cases like disabling checks mid-migration and check validation
🌿Good first issues
- Add test coverage for
schema_dumper.rb(lib/strong_migrations/schema_dumper.rb)—there's a file with no corresponding test file in test/, suggesting schema alphabetization logic needs validation - Expand
error_messages.rbwith additional context for MySQL/MariaDB-specific errors (COPY algorithm, locking strategies). Several checks exist in adapters but may lack user-friendly guidance - Create a comprehensive test for the
migrator.rbfile which orchestrates migration context and execution; this file is mentioned in file structure but not obvious which test covers it
⭐Top contributors
Click to expand
Top contributors
📝Recent commits
Click to expand
Recent commits
2e8bc96— Version bump to 2.7.0 [skip ci] (ankane)6c55ccb— Updated test style to match error message (ankane)1fe1b87— Updated readme style to match error message [skip ci] (ankane)a8fcfcb— Updated style [skip ci] (ankane)1f4ee37— Moved comment [skip ci] (ankane)693f832— Updated skip comment [skip ci] (ankane)7354f82— Improved error message for callable default values (ankane)c2b3494— Improved error message for callable default values (ankane)15b6a55— Removed comment that applies to Postgres < 11 [skip ci] (ankane)c9a2a29— Improved error message (ankane)
🔒Security observations
Strong Migrations is a defensive security tool for Rails applications with a solid security posture. The codebase primarily performs static analysis on migration files to prevent unsafe database operations. No critical vulnerabilities detected. The tool itself has minimal external dependencies and focuses on pattern detection rather than execution. Recommendations focus on ongoing input validation practices and gem signature verification for users. The project follows security best practices for a developer-tool gem.
- Low · Dynamic SQL Query Construction in Migration Checks —
lib/strong_migrations/checks.rb, lib/strong_migrations/adapters/*. The codebase performs static analysis on Rails migrations to detect unsafe patterns. While the tool itself is defensive, the checker logic in lib/strong_migrations/checks.rb and related adapters may parse and analyze raw SQL queries. If migration files contain user-influenced SQL, there could be indirect SQL injection risks, though this is mitigated by the fact that migrations are typically developer-controlled. Fix: Continue validating that all migration analysis doesn't execute user input. Ensure migration files are only modifiable by trusted developers through code review processes. - Low · No Evidence of Input Validation in Custom Migration Checks —
lib/strong_migrations/checker.rb, lib/strong_migrations/migration_context.rb. The lib/strong_migrations/checker.rb and migration context files handle migration metadata and arguments. While Rails migrations have built-in protections, custom check implementations should validate inputs before processing. Fix: Review input validation in custom check implementations. Ensure all user-supplied migration parameters are validated before use in any string operations. - Low · No CHANGELOG Entry Verification —
gemfiles/, strong_migrations.gemspec. The CHANGELOG.md file exists but there's no evidence of signed releases or version verification. Users installing via gem should verify gem signatures. Fix: Recommend users verify gem signatures:gem install strong_migrations -P MediumSecurity. Consider implementing gem signing in the build pipeline (.github/workflows/build.yml). - Low · Incomplete Access Control in Test Suite —
test/ directory. Test files in test/ directory are world-readable. While test files are typically not sensitive, they contain examples of migration patterns that could be informative to attackers. Fix: Ensure test files don't contain sensitive data or credentials. Current structure appears safe, but maintain this practice.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.