Skip to main content

Safe migrations for production PostgreSQL databases

Project description

🛡️ migsafe

Safe Alembic migrations for production PostgreSQL databases

Python Version License Code Style CI PyPI version Codecov

migsafe (v0.4.0) is a CLI tool and CI linter that analyzes Alembic and Django migrations before they are applied and warns about dangerous, slow, and blocking schema changes.

Project goal — catch migration problems before deployment, not during production downtime.


📋 Contents


❓ Why it’s needed

Alembic makes migrations convenient, but not safe by default.

Typical problems migsafe catches early:

Problem Consequences
ADD COLUMN NOT NULL DEFAULT Rewrites the entire table
CREATE INDEX without CONCURRENTLY Blocks writes
ALTER COLUMN TYPE Long exclusive lock
DROP COLUMN Data loss
Raw op.execute() Dangerous SQL (UPDATE/DELETE without WHERE, DDL without CONCURRENTLY)
Data migrations without batching Long-lasting locks (large INSERTs without LIMIT)

💡 This may “work” on a small database.
⚠️ In production — downtime, night deployments, and emergency rollbacks.


✨ What migsafe does

Capability Description
🔍 AST analysis Analyzes Alembic migrations via AST
🧠 Smart detection Determines real migration behavior, not just its code
🔎 SQL analysis Analyzes SQL in op.execute() for dangerous patterns (DDL, JOINs, subqueries, CTEs)
⚠️ Risk classification OK / WARNING / CRITICAL
💥 CI integration Fails CI if a migration is dangerous
💡 Recommendations Suggests how to rewrite migrations safely
🔧 Autofix Automatically fixes some issues with backup creation
📊 Statistics Collects statistics and metrics across all migrations
⚙️ Configuration Flexible configuration via JSON/TOML
🎯 Snapshot execution Runs migrations on production DB snapshots and measures metrics
📜 History analysis Analyzes migration history via Git to detect problematic patterns
🐍 Django support Analyzes Django migrations alongside Alembic
🔌 Plugin system Create custom analysis rules via plugins

Code is not executed.
Database is not touched.
Analysis is completely safe.


📦 Installation

From PyPI (recommended)

# Basic installation
pip install migsafe

# With optional dependencies for snapshot execution
pip install migsafe[executors]

# With optional dependencies for improved text output
pip install migsafe[formatters]

# All optional dependencies
pip install migsafe[executors,formatters]

From source (for development)

git clone https://github.com/SuccubHunter/migsafe.git
cd migsafe
pip install -e .

# Or with optional dependencies
pip install -e ".[executors,formatters]"

Requirements: Python >= 3.8

Optional dependencies:

  • executors — for migsafe execute (requires psycopg2-binary, alembic, sqlalchemy)
  • formatters — improved text output (requires rich)

🚀 Quick start

Basic usage

In a project directory with Alembic:

migsafe analyze

Analyze specific files/directories

# Analyze a directory
migsafe analyze migrations/

# Analyze a specific file
migsafe analyze migrations/versions/001_add_user.py

Save report

# HTML report
migsafe analyze --format html --output report.html

# JSON report
migsafe analyze --format json --output report.json

Available output formats: text (default), json, html, junit, sarif

Automatic fixes

migsafe can automatically fix some issues:

# Show fixes (dry-run)
migsafe analyze --autofix

# Apply fixes (creates backup)
migsafe analyze --autofix --apply

# Apply without confirmation
migsafe analyze --autofix --apply --yes

# Apply without backup (not recommended)
migsafe analyze --autofix --apply --no-backup

Supported fixes:

  • ADD COLUMN NOT NULL → safe pattern (nullable → backfill → NOT NULL)
  • CREATE INDEX → add CONCURRENTLY
  • DROP INDEX → add CONCURRENTLY

Configuration file

You can configure migsafe using a config file:

migsafe.json:

{
  "exclude": ["**/test_*.py", "**/__pycache__/**"],
  "format": "json",
  "severity": "warning",
  "no_color": true,
  "exit_code": true
}

migsafe.toml:

[migsafe]
exclude = ["**/test_*.py", "**/__pycache__/**"]
format = "json"
severity = "warning"
no_color = true
exit_code = true

Usage:

migsafe analyze --config migsafe.json

CLI parameters override configuration file settings.

Migration statistics

The migsafe stats command collects and analyzes migration statistics:

# Show overall statistics
migsafe stats

# Statistics for a specific migration
migsafe stats --migration 001_add_users.py

# Export to JSON
migsafe stats --format json --output stats.json

# Export to CSV
migsafe stats --format csv --output stats.csv

# Filter by severity
migsafe stats --severity critical

# Filter by rule
migsafe stats --rule add_column_not_null_rule

What statistics show:

  • Total number of migrations and issues
  • Distribution by issue type and severity
  • Top issues and rules by frequency
  • Automatic recommendations to improve migration practices

Available formats: text (default), json, csv

Demo project

To see the library in action:

python demo/run_demo.py

The demo includes examples of dangerous and safe migrations. See demo/README.md.

New features in version 0.4

Running migrations on snapshots

Execute migrations on production DB snapshots to measure real performance metrics:

⚠️ Required: To use migsafe execute, install optional dependencies: pip install migsafe[executors]

# Create a snapshot and run migration
migsafe execute migration.py --snapshot-url postgresql://user:pass@localhost/db

# Run on an existing snapshot
migsafe execute migration.py --snapshot-url postgresql://user:pass@localhost/db \
    --snapshot-name my_snapshot

# Save results to JSON
migsafe execute migration.py --snapshot-url postgresql://user:pass@localhost/db \
    --format json --output results.json

📄 Detailed guide

Git-based migration history analysis

Track migration changes over time to detect problematic patterns:

# Analyze full migration history
migsafe history

# Analyze a specific migration
migsafe history --migration migrations/001_add_user.py

# Filter by date
migsafe history --since 2025-01-01 --until 2025-12-31

# Filter by author
migsafe history --author "Ivan Ivanov"

📄 Detailed guide

Django migration support

Analyze Django migrations alongside Alembic:

# Auto-detect Django migrations
migsafe analyze

# Analyze migrations of a specific app
migsafe analyze --django-app myapp

# Analyze multiple apps
migsafe analyze --django-app myapp --django-app otherapp

📄 Detailed guide

Plugins

Load custom analysis rules via plugins:

# Use plugins from directory
migsafe analyze --plugins-dir ./plugins

# List loaded plugins
migsafe plugins list

# Plugin info
migsafe plugins info my-plugin

📄 Detailed guide


📊 Output example

Migration: 2025_12_31_add_email.py

[CRITICAL] add_column_not_null
Table: users
Column: email

Message:
Adding NOT NULL column 'email' to table 'users' rewrites entire table and blocks writes in PostgreSQL

Recommendation:
Use safe pattern:
1) Add column as nullable: op.add_column(..., nullable=True)
2) Backfill data in batches: op.execute('UPDATE ... WHERE ...')
3) Set NOT NULL constraint: op.alter_column(..., nullable=False)

🔧 Using in CI/CD

Quick start

For CI/CD integration, use migsafe lint, which returns a non-zero exit code if critical issues are found:

migsafe lint --format junit --output report.xml --no-color

Behavior

Level Exit Code Behavior
CRITICAL 1 Build fails (migsafe lint or migsafe analyze --exit-code)
WARNING 0 Build passes with warnings
OK 0 Build passes

💡 Note: migsafe lint automatically returns a non-zero exit code on critical issues, making it ideal for CI/CD.

Integration examples

Ready-to-use configs for various CI/CD systems are available in examples/ci/:

(…content continues unchanged…)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

migsafe-0.4.0.tar.gz (177.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

migsafe-0.4.0-py3-none-any.whl (135.9 kB view details)

Uploaded Python 3

File details

Details for the file migsafe-0.4.0.tar.gz.

File metadata

  • Download URL: migsafe-0.4.0.tar.gz
  • Upload date:
  • Size: 177.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for migsafe-0.4.0.tar.gz
Algorithm Hash digest
SHA256 337420691472c98603854f1c9a2451aeede4c2c7fb5c1aa0fe875da8f3c6b497
MD5 bb17bb18fbbd473157d94ed1b2d0c64a
BLAKE2b-256 a390daacc1a77e90d5cf1c91c194538c4104fabcd9b9893195ff08f8626f00ae

See more details on using hashes here.

File details

Details for the file migsafe-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: migsafe-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 135.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for migsafe-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cf1a6d3a4abad2ed5f473dc56868639550a30b0452a12cbe5aebfe4ebedf687a
MD5 5f43c44fa97e0b359ffd663a9bc85d09
BLAKE2b-256 165fc80f758504e24ae4bb0aa48db737ff863d01b6a49cacb710c93325f2bd20

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page