{"id":158,"library":"alembic","title":"Alembic","description":"Database migration tool for SQLAlchemy. Manages schema versioning via migration scripts. Current version: 1.18.4 (Mar 2026). Tightly coupled to SQLAlchemy — version mismatch causes silent failures. SQLAlchemy 1.3 dropped in Alembic 1.15. Python 3.8 dropped in Alembic 1.15. The #1 footgun: autogenerate generates empty migrations when target_metadata is not correctly set in env.py.","status":"active","version":"1.18.4","language":"python","source_language":"en","source_url":"https://github.com/sqlalchemy/alembic","tags":["alembic","sqlalchemy","migrations","database","python","schema"],"install":[{"cmd":"pip install alembic","lang":"bash","label":"Python"}],"dependencies":[{"reason":"Required. Alembic 1.15+ requires SQLAlchemy >= 1.4. SQLAlchemy 2.0 fully supported.","package":"sqlalchemy","optional":false},{"reason":"Required for migration script templates. Installed automatically.","package":"Mako","optional":false}],"imports":[{"note":"The single most common Alembic mistake. If target_metadata = None in env.py, autogenerate produces empty migration files. Must import your models and set target_metadata = Base.metadata.","wrong":"# In alembic/env.py\ntarget_metadata = None  # default — autogenerate generates EMPTY migrations","symbol":"env.py target_metadata","correct":"# In alembic/env.py — MUST import your models for autogenerate to work\nfrom myapp.models import Base  # import all models so metadata is populated\ntarget_metadata = Base.metadata\n\n# If models are in multiple files, import them all:\nfrom myapp.models.user import User\nfrom myapp.models.post import Post\n# then:\ntarget_metadata = Base.metadata"},{"note":"Must run 'alembic upgrade head' before running --autogenerate again. Error: 'Target database is not up to date' means DB is behind the migration chain.","wrong":"# Wrong: running autogenerate before DB is up to date\nalembic revision --autogenerate -m 'add column'  # fails if DB not at head","symbol":"alembic init + upgrade","correct":"# CLI commands — run from project root\nalembic init alembic          # create alembic directory\nalembic revision --autogenerate -m 'initial'  # generate migration\nalembic upgrade head           # apply all pending migrations\nalembic downgrade -1           # roll back one migration\nalembic history                # show migration history\nalembic current                # show current DB version"}],"quickstart":{"code":"# 1. Install and init\n# pip install alembic sqlalchemy\n# alembic init alembic\n\n# 2. Edit alembic/env.py — add your models:\n# from myapp.models import Base\n# target_metadata = Base.metadata\n\n# 3. Edit alembic.ini — set database URL:\n# sqlalchemy.url = postgresql://user:pass@localhost/mydb\n\n# 4. Generate first migration\n# alembic revision --autogenerate -m 'initial schema'\n\n# 5. Apply migration\n# alembic upgrade head\n\n# Migration file (alembic/versions/xxx_initial_schema.py):\nfrom alembic import op\nimport sqlalchemy as sa\n\ndef upgrade():\n    op.create_table(\n        'users',\n        sa.Column('id', sa.Integer, primary_key=True),\n        sa.Column('username', sa.String(50), nullable=False),\n        sa.Column('email', sa.String(120), nullable=False),\n    )\n\ndef downgrade():\n    op.drop_table('users')","lang":"python","description":"Alembic setup and first migration workflow."},"warnings":[{"fix":"In env.py: import your models then set target_metadata = Base.metadata","message":"target_metadata = None in env.py causes autogenerate to produce completely empty migration files. This is the default after 'alembic init'. Must be changed to Base.metadata.","severity":"breaking","affected_versions":"all"},{"fix":"Run 'alembic upgrade head' first, then run --autogenerate.","message":"'Target database is not up to date' error when running --autogenerate. DB must be at head before generating new migrations.","severity":"breaking","affected_versions":"all"},{"fix":"Use SQLAlchemy >= 1.4 and Python >= 3.9 with Alembic 1.15+","message":"SQLAlchemy 1.3 support dropped in Alembic 1.15. Python 3.8 support dropped in Alembic 1.15.","severity":"breaking","affected_versions":">= 1.15"},{"fix":"Always run 'alembic check' and manually review generated migration files before applying.","message":"Autogenerate cannot detect everything. It misses: stored procedures, views, partial indexes (pre-1.12), CHECK constraints, column defaults (in some cases). Always manually review generated migrations.","severity":"gotcha","affected_versions":"all"},{"fix":"Run 'alembic merge heads -m merge' to create a merge migration. Then 'alembic upgrade head'.","message":"Multiple heads error: 'Multiple head revisions are present' when two migrations both point to the same parent. Happens when multiple developers generate migrations from the same base.","severity":"gotcha","affected_versions":"all"},{"fix":"Import all model files in env.py before target_metadata = Base.metadata.","message":"Autogenerate generates 'create table' for all tables instead of 'add column' when models are not imported before autogenerate runs. Models must be imported in env.py so SQLAlchemy metadata is populated.","severity":"gotcha","affected_versions":"all"},{"fix":"In env.py: config.set_main_option('sqlalchemy.url', os.environ['DATABASE_URL'])","message":"alembic.ini sqlalchemy.url hardcodes the database URL. For production, override it in env.py using environment variables.","severity":"gotcha","affected_versions":"all"},{"fix":"Always use a virtual environment (e.g., `python -m venv .venv`) to install Python packages to avoid permission issues and system package manager conflicts. Avoid running pip commands with `sudo` unless absolutely necessary for system-wide tools, which is generally not recommended for application dependencies.","message":"Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead.","severity":"gotcha","affected_versions":"all"},{"fix":"It is recommended to use a virtual environment or run pip as a non-root user. If running as root is intentional, use the `--root-user-action` option to suppress this warning.","message":"Running pip as root can lead to broken permissions and conflicts with the system package manager, potentially rendering the system unusable.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T09:08:14.444Z","next_check":"2026-06-24T00:00:00.000Z","problems":[{"fix":"pip install alembic","cause":"Alembic is not installed in the Python environment.","error":"ModuleNotFoundError: No module named 'alembic'"},{"fix":"Ensure the correct import path in env.py, e.g., 'from src.infra.sqlalchemy.config.database import Base'.","cause":"The 'infra' module is not found due to incorrect import paths in env.py.","error":"ModuleNotFoundError: No module named 'infra'"},{"fix":"Add 'sys.path.append(os.path.abspath(os.path.dirname(__file__)))' in env.py to include the project directory in sys.path.","cause":"Alembic cannot locate the 'backend' module due to missing sys.path configuration.","error":"ModuleNotFoundError: No module named 'backend'"},{"fix":"Ensure that the database engine is correctly configured and connected in env.py.","cause":"This error occurs when a database connection is not properly established, leading to a NoneType object where a database engine is expected.","error":"AttributeError: 'NoneType' object has no attribute 'execute'"},{"fix":"Ensure all SQLAlchemy model files are imported into alembic/env.py and that `target_metadata` is correctly assigned to your application's `MetaData` object (e.g., `target_metadata = Base.metadata`). Avoid using `Base.metadata.create_all()` for schema creation in environments managed by Alembic.","cause":"Alembic's autogenerate feature produces an empty migration because target_metadata is not correctly set in env.py, preventing it from seeing your SQLAlchemy models, or because Base.metadata.create_all() was used in your application, creating tables directly and thus making Alembic believe no migrations are needed.","error":"No changes detected (alembic revision --autogenerate produces empty migration file)"}],"ecosystem":"pypi","meta_description":null,"install_score":80,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"45.6M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"44M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"51.2M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"50M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"42.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"41M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"41.8M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"40M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"44.2M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":"43M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}