Database Migration Strategy Using Alembic for Production Deployments in LMForge

The LMForge platform implements a robust database migration strategy using Alembic via Flask-Migrate to manage PostgreSQL schema changes in production, automating versioned upgrades during containerized deployments while supporting programmatic rollbacks.

The LMForge end-to-end LLMOps platform for multi-model agents relies on PostgreSQL for persistent storage and employs a structured database migration strategy using Alembic for production deployments. By integrating Flask-Migrate into the HTTP service layer, the system ensures schema consistency across releases through version-controlled migration scripts and automated CI/CD pipeline execution.

Architecture of the Alembic Migration System

Migration Environment Configuration

The core migration logic resides in api/internal/migration/env.py, which configures the Alembic environment to work with the Flask-SQLAlchemy engine. At lines 18–25, the script detects the Flask-SQLAlchemy version and obtains the database engine from the running application context, ensuring compatibility across both legacy (< 3) and modern (≥ 3) versions of the library.

The environment script then injects the connection URL into Alembic’s configuration at line 39, ensuring migrations target the correct PostgreSQL instance. It also binds the target metadata using target_metadata = get_metadata(), enabling Alembic’s autogeneration capabilities to detect schema changes from the Flask-SQLAlchemy db object.

Flask-Migrate Integration

The HTTP server constructor in api/internal/server/http.py (line 44) registers Flask-Migrate with the application by calling migrate.init_app(self, db, directory="internal/migration"). This wires Alembic into the Flask lifecycle, pointing it at the internal migration directory that houses all version scripts and configuration files.

Production Deployment Workflow

Pre-Deployment Migration Execution

During a production rollout, the CI/CD pipeline executes migration commands after the new container starts but before traffic is directed to it. This guarantees the database schema matches the deployed code version. The standard command uses Flask-Migrate:

flask db upgrade

Alternatively, teams can invoke Alembic directly using the configuration file:

alembic -c api/internal/migration/alembic.ini upgrade head

To verify the current database revision after deployment, run:

flask db current

Rollback Procedures

If a deployment requires reversion, the system supports stepping back to previous schema versions. The command flask db downgrade -1 steps back one revision, while direct Alembic access provides the same capability:

alembic -c api/internal/migration/alembic.ini downgrade -1

Versioned Schema Change Management

All schema modifications live as Python scripts under api/internal/migration/versions/. Each file contains explicit upgrade() and downgrade() functions generated by Alembic. For example, the migration file 0a9f4c627c6b_.py (lines 19–40) creates the app_config table and adds foreign-key columns to the app table, providing reversible operations for both deployment and rollback scenarios.

Programmatic Migration Control

While production deployments typically use CLI commands, the system supports running migrations programmatically within Python contexts. The following pattern matches the initialization logic found in the HTTP service:

from flask import Flask
from flask_migrate import Migrate
from pkg.sqlalchemy import SQLAlchemy
from alembic import command
from alembic.config import Config

app = Flask(__name__)
db = SQLAlchemy()
migrate = Migrate()

# Initialize extensions (equivalent to Http.__init__)

db.init_app(app)
migrate.init_app(app, db, directory="api/internal/migration")

# Run upgrade programmatically

alembic_cfg = Config("api/internal/migration/alembic.ini")
command.upgrade(alembic_cfg, "head")

In containerized environments, migrations typically execute via Docker exec:

docker exec -it llmops_api flask db upgrade

Summary

  • Engine Discovery: The env.py script dynamically retrieves the SQLAlchemy engine from the Flask app, handling version compatibility across Flask-SQLAlchemy releases.
  • URL Injection: Database connection strings are rendered and injected into Alembic’s configuration at runtime to ensure correct target selection.
  • Flask Integration: The HTTP service initializes Flask-Migrate at line 44, binding Alembic to the application lifecycle and the internal/migration directory.
  • Version Control: Schema changes are tracked in api/internal/migration/versions/ with reversible upgrade() and downgrade() functions.
  • Dependencies: Requires alembic==1.15.1 and flask-migrate as specified in api/requirements.txt.

Frequently Asked Questions

How does LMForge handle database migrations during containerized deployments?

The CI/CD pipeline executes flask db upgrade inside the new container immediately after startup but before the load balancer routes traffic to the instance. This ensures the PostgreSQL schema is synchronized with the application code before the service accepts requests, preventing runtime errors from schema mismatches.

What is the difference between using flask db upgrade and direct Alembic commands?

flask db upgrade is a Flask-Migrate wrapper that automatically configures Alembic using the Flask application context and the migration directory specified in api/internal/server/http.py. Direct commands like alembic -c api/internal/migration/alembic.ini upgrade head require manual specification of the configuration file but function identically under the hood.

How does the migration system handle different Flask-SQLAlchemy versions?

The api/internal/migration/env.py file contains compatibility logic at lines 18–25 that detects whether the installed Flask-SQLAlchemy version is below 3 or 3 and above. It adjusts the engine retrieval method accordingly, ensuring the migration environment works regardless of the specific SQLAlchemy version deployed.

Can migrations be run programmatically within the application code?

Yes, though this is rare in production. The system supports importing alembic.command and alembic.config.Config to execute upgrades or downgrades within Python scripts. This pattern mirrors the initialization found in the HTTP service constructor and requires the same configuration path (api/internal/migration/alembic.ini) used by the CLI tools.

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 →