migra: PostgreSQL Schema Migration

3.0.1663481299 · active · verified Fri Apr 17

migra is a Python library that functions like `diff` for PostgreSQL schemas. It compares two PostgreSQL databases (or SQLAlchemy metadata objects) and generates the SQL statements necessary to migrate one to the other, making schema management and deployment safer and more explicit. The current version is 3.0.1663481299, with releases following active development.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart compares a defined SQLAlchemy `MetaData` schema with a live (potentially empty) target PostgreSQL database. It generates the DDL needed to make the target schema match the source. Remember to set `POSTGRES_SOURCE_URL` and `POSTGRES_TARGET_URL` environment variables to your actual PostgreSQL connection strings. Always review the generated SQL before applying it to a production database.

import os
from migra import Migration
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String

# Use environment variables for PostgreSQL connection strings for safety
# Ensure POSTGRES_SOURCE_URL and POSTGRES_TARGET_URL are set to real PostgreSQL databases.
# For a demo, you can point them to two different databases on the same host,
# or create a temporary 'source' schema and an empty 'target' schema.
source_url = os.environ.get('POSTGRES_SOURCE_URL', 'postgresql+psycopg2://user:pass@localhost:5432/source_db')
target_url = os.environ.get('POSTGRES_TARGET_URL', 'postgresql+psycopg2://user:pass@localhost:5432/target_db')

# Establish SQLAlchemy engines
source_engine = create_engine(source_url)
target_engine = create_engine(target_url)

# Define a simple schema for the "source" database (what we want the target to look like)
source_metadata = MetaData()
Table('users', source_metadata,
      Column('id', Integer, primary_key=True),
      Column('name', String(50), nullable=False),
      Column('email', String(100), unique=True))

# Apply the source schema to the source database (if not already there)
print("Ensuring source schema exists in source_db...")
with source_engine.connect() as conn:
    source_metadata.create_all(conn)
    conn.commit()

# The target database is assumed to be empty or have an older schema.
# migra will generate SQL to make target look like source.

# Create a Migration object to compare the live schemas
m = Migration(source=source_engine, target=target_engine)

# Get the DDL statements to transform target to source
sql_statements = m.statements

print("\nGenerated SQL statements to migrate target_db to source_db schema:")
if sql_statements:
    for stmt in sql_statements:
        print(stmt)
    # To apply the migration to the target database (UNCOMMENT WITH EXTREME CAUTION!)
    # print("\nApplying migration to target database...")
    # with target_engine.connect() as conn:
    #    m.apply(conn)
    #    conn.commit()
    # print("Migration applied successfully.")
else:
    print("No migration statements needed (schemas are identical or target is already ahead).")

view raw JSON →