Langflow Database Migrations and ORM Models: Implementation Guide
Langflow uses SQLModel (a SQLAlchemy wrapper with Pydantic validation) as its ORM and Alembic for schema migrations, implementing an async-compatible migration environment with expand-contract safety validation.
Langflow, the open-source visual framework for building LLM applications, requires robust data persistence for flows, users, and messages. According to the langflow-ai/langflow source code, the project implements a sophisticated database layer using SQLModel for type-safe ORM operations and Alembic for version-controlled schema evolution. This architecture supports both SQLite and PostgreSQL backends through an async engine pattern while enforcing strict migration safety protocols.
How Langflow Manages Database Migrations
The DatabaseService Migration Engine
Located in src/backend/base/langflow/services/database/service.py, the DatabaseService class serves as the central orchestrator for database connectivity and migration execution. The service initializes an async engine using SQLAlchemy's create_async_engine, automatically rewriting database URLs to use appropriate async drivers—sqlite+aiosqlite for SQLite and postgresql+psycopg for PostgreSQL.
self.engine = create_async_engine(
self.database_url,
connect_args=self._get_connect_args(),
**kwargs,
)
The service configures an async session factory using SQLModelAsyncSession to ensure compatibility with SQLModel's query interface:
self.async_session_maker = async_sessionmaker(
self.engine,
class_=SQLModelAsyncSession,
expire_on_commit=False,
)
When run_migrations() is invoked, the service delegates to Alembic's command API, loading the environment configuration from src/backend/base/langflow/alembic/env.py and executing upgrades or downgrades against the async engine.
Alembic Environment Configuration
The Alembic environment script at src/backend/base/langflow/alembic/env.py bridges Alembic with Langflow's SQLModel metadata. The critical line exposing all ORM entities to Alembic is:
target_metadata = SQLModel.metadata
This metadata object automatically collects all table definitions from SQLModel classes, enabling autogeneration of migration scripts. The environment handles async operations through async_engine_from_config, executing migrations within an async context using await connection.run_sync(_do_run_migrations).
For PostgreSQL deployments, the environment implements distributed locking via advisory locks based on the LANGFLOW_MIGRATION_LOCK_NAMESPACE environment variable, preventing concurrent migration execution in multi-instance deployments.
Expand-Contract Migration Validation
Langflow enforces database schema safety through src/backend/base/langflow/alembic/migration_validator.py, which implements the expand-contract pattern. This validator parses migration files using Python's ast module to ensure changes follow a three-phase approach:
- EXPAND: Add new columns or tables
- MIGRATE: Backfill or transform existing data
- CONTRACT: Remove deprecated columns or tables
The validator flags unsafe operations—such as adding non-nullable columns without defaults or dropping columns outside the CONTRACT phase—generating structured reports that enable CI pipelines to reject risky migrations before deployment.
Langflow ORM Models and Structure
SQLModel-Based Entity Layer
Langflow's persistence layer uses SQLModel, which combines SQLAlchemy's ORM capabilities with Pydantic's data validation. All models reside under src/backend/base/langflow/services/database/models/ and inherit from SQLModel with table=True.
Primary entities include:
- User (
models/user/model.py): Stores authentication credentials, superuser flags, and relationships to API keys and flows - Flow (
models/flow/model.py): Contains flow definitions as JSON graphs, linked to users and folders - Message (
models/message/model.py): Persists conversation history with role and content fields - Variable (
models/variable/model.py): Key-value storage for user-specific configuration - File (
models/file/model.py): Metadata for uploaded files including path and ownership - Job (
models/jobs/model.py): Background task execution tracking - ApiKey (
models/api_key/model.py): Authentication tokens linked to users - Folder (
models/folder/model.py): Hierarchical organization of flows - SSOUserProfile / SSOConfig (
models/auth/sso.py): External authentication provider integration
Model Relationships and Field Definitions
Models define columns using SQLModel's Field and relationships using Relationship. For example, the User model establishes bidirectional relationships with API keys:
class User(SQLModel, table=True): # src/backend/base/langflow/services/database/models/user/model.py
id: UUIDstr = Field(default_factory=uuid4, primary_key=True, unique=True)
username: str = Field(index=True, unique=True)
api_keys: list["ApiKey"] = Relationship(back_populates="user")
The SQLModel.metadata object collects all these definitions, making them available to Alembic for schema generation. JSON fields store complex structures like flow graphs and message content, while indexed fields optimize lookup performance for usernames and flow names.
Running Database Migrations in Langflow
The typical migration workflow involves generating revisions through a helper script and validating them against the expand-contract rules:
# Generate a new migration from model changes
scripts/generate_migration.py "add is_active to User"
# Validate migration safety in CI
pytest src/backend/base/langflow/alembic/test_migration_validator.py
# Execute migrations
python -m langflow.services.database.migrate upgrade head
The generate_migration.py script wraps Alembic's revision --autogenerate command, ensuring new files are placed in src/backend/base/langflow/alembic/versions/ with proper naming conventions.
Summary
- Langflow uses SQLModel (SQLAlchemy-based) for type-safe ORM operations with Pydantic validation
- Alembic handles schema migrations through a custom async environment in
src/backend/base/langflow/alembic/env.py - The DatabaseService (
service.py) manages async engines and sessions, supporting both SQLite and PostgreSQL - MigrationValidator enforces the expand-contract pattern (EXPAND → MIGRATE → CONTRACT) to prevent unsafe schema changes
- Core entities include User, Flow, Message, Variable, File, Job, ApiKey, Folder, and SSO-related models
- PostgreSQL deployments support distributed locking via
LANGFLOW_MIGRATION_LOCK_NAMESPACE
Frequently Asked Questions
What ORM does Langflow use for database operations?
Langflow uses SQLModel, a library that combines SQLAlchemy's ORM functionality with Pydantic's data validation. This allows models to serve as both database schemas and API request/response objects. The models are defined in files under src/backend/base/langflow/services/database/models/ using SQLModel's declarative syntax with table=True.
How does Langflow handle database schema changes?
Schema changes are managed through Alembic with a custom async-compatible environment. The DatabaseService class creates an async engine and invokes Alembic commands through run_migrations(). All migrations must pass the MigrationValidator, which checks for expand-contract phase markers (EXPAND, MIGRATE, CONTRACT) to ensure zero-downtime deployments.
Does Langflow support PostgreSQL and SQLite simultaneously?
Yes. The DatabaseService in service.py automatically detects the database URL and configures the appropriate async driver—sqlite+aiosqlite for SQLite or postgresql+psycopg for PostgreSQL. The same SQLModel definitions and Alembic migrations work across both backends, though PostgreSQL deployments additionally support advisory locking for multi-instance migration safety.
Where are the database models defined in the Langflow repository?
All ORM models reside in src/backend/base/langflow/services/database/models/, with each entity typically having its own subdirectory. For example, the User model is in models/user/model.py, the Flow model in models/flow/model.py, and the Message model in models/message/model.py. These models are automatically registered in SQLModel.metadata for Alembic to track schema changes.
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 →