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 the alembic init step.
  • Configure src/migrations/env.py to import engine from src/app/core/db/database.py and Base.metadata from src/app/core/db/models.py.
  • Use alembic revision --autogenerate to create migration scripts based on model changes in src/app/models/.
  • Apply changes with alembic upgrade head and roll back with alembic downgrade -1.
  • Optionally trigger migrations automatically using @app.on_event("startup") in src/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →