How to Integrate Alembic for Database Migrations in FastAPI Boilerplate
The fastapi-boilerplate repository provides a pre-configured Alembic setup in src/migrations/ that connects to the existing SQLAlchemy engine in src/app/core/db/database.py, allowing you to generate and apply database migrations using standard Alembic CLI commands.
The fastapi-boilerplate repository by benavlabs implements a clean, modular architecture that separates database concerns into distinct packages. Integrating Alembic for database migrations ensures your schema evolves safely alongside your SQLAlchemy models defined in src/app/models/. This guide walks through connecting Alembic to the existing database configuration, generating migration scripts, and automating schema updates.
Configure the Alembic Environment
Alembic’s configuration lives in src/migrations/env.py. This file must import the existing SQLAlchemy engine so that Alembic knows which database to target, and it must reference the metadata object containing all model definitions.
First, import the application’s database engine and base metadata:
# src/migrations/env.py
from logging.config import fileConfig
from sqlalchemy import engine_from_config, pool
from alembic import context
# Import the app's SQLAlchemy engine
from src.app.core.db.database import engine
# Import the Base metadata
from src.app.core.db.models import Base
target_metadata = Base.metadata
Why this works: The boilerplate already creates the engine in src/app/core/db/database.py. Re-using it avoids duplicate connection settings. Base.metadata aggregates every model declared in src/app/models/, ensuring Alembic can autogenerate migrations for all tables.
Generate Migration Scripts
Whenever you add or modify an ORM model (for example, adding a column to src/app/models/user.py), generate a migration script using the autogenerate command:
alembic revision --autogenerate -m "Add email_verified to User"
This command reads target_metadata from env.py, compares it to the current database schema, and writes a new revision file under src/migrations/versions/.
Apply and Roll Back Migrations
Run the migration scripts against the configured database to move the schema forward:
alembic upgrade head
The head alias points to the latest revision. To roll back the most recent migration:
alembic downgrade -1
Automate Migrations on Startup (Optional)
You can ensure migrations run automatically when the FastAPI application starts by adding a startup hook in src/app/main.py:
# src/app/main.py
from pathlib import Path
from alembic import command
from alembic.config import Config
from fastapi import FastAPI
app = FastAPI()
def run_migrations() -> None:
alembic_cfg = Config(str(Path(__file__).parent.parent / "migrations" / "alembic.ini"))
command.upgrade(alembic_cfg, "head")
@app.on_event("startup")
def on_startup() -> None:
run_migrations()
Because the boilerplate configures the SQLAlchemy engine in src/app/core/db/database.py, the migration run shares the same connection details defined in your environment.
Keep Configuration Synchronized
If you change the database URL (for example, switching from SQLite to PostgreSQL), update src/migrations/alembic.ini. The sqlalchemy.url entry should reference the same environment variable that database.py uses (DATABASE_URL).
Complete Working Example
Here is an end-to-end example of adding a new Post model to the database:
Step 1: Define the model in src/app/models/post.py:
# src/app/models/post.py
from sqlalchemy import Column, Integer, String, ForeignKey
from src.app.core.db.models import Base
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, nullable=False)
content = Column(String, nullable=False)
author_id = Column(Integer, ForeignKey("users.id"))
Step 2: Generate the migration:
alembic revision --autogenerate -m "Create posts table"
Step 3: Apply the migration:
alembic upgrade head
Summary
- The fastapi-boilerplate ships with a pre-populated
src/migrations/directory, so you can skip thealembic initstep. - Configure
src/migrations/env.pyto importenginefromsrc/app/core/db/database.pyandBase.metadatafromsrc/app/core/db/models.py. - Use
alembic revision --autogenerateto create migration scripts based on model changes insrc/app/models/. - Apply changes with
alembic upgrade headand roll back withalembic downgrade -1. - Optionally trigger migrations automatically using
@app.on_event("startup")insrc/app/main.py.
Frequently Asked Questions
How do I connect Alembic to an existing database in the boilerplate?
Import the existing SQLAlchemy engine from src/app/core/db/database.py and the Base metadata from src/app/core/db/models.py inside src/migrations/env.py. Set target_metadata = Base.metadata so Alembic can read all model definitions and compare them against the current database schema.
Where are the migration files stored in this project?
Migration scripts are stored in src/migrations/versions/. The env.py file in src/migrations/ handles the runtime configuration, while alembic.ini contains the main configuration settings including the database URL.
Can I run migrations automatically when the app starts?
Yes. Import alembic.command and alembic.config.Config in src/app/main.py, then create a function that loads src/migrations/alembic.ini and runs command.upgrade(alembic_cfg, "head"). Attach this function to the FastAPI startup event using @app.on_event("startup").
What should I do if I change the database URL environment variable?
Update the sqlalchemy.url value in src/migrations/alembic.ini to match the new connection string. Ensure it references the same DATABASE_URL environment variable used by src/app/core/db/database.py to keep the application and migration tool synchronized.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →