Database Migration Guide
How to create and manage database migrations in the Zyeta backend
This guide outlines the process for creating and managing database migrations in the Zyeta backend using Alembic.
Overview
Zyeta uses Alembic to manage database migrations. Alembic is an SQL migration tool for SQLAlchemy that provides:
- Version control for database schemas
- Ability to upgrade and downgrade between versions
- Auto-generation of migrations based on model changes
- A flexible environment for migration script execution
The database migration system follows a numbered sequence approach, with each migration file prefixed with a sequential number (e.g., 001_create_base_tables.py
, 002_create_models_and_agents.py
).
Migration Workflow Visualization
Setup
The Alembic configuration is in the project root directory:
alembic.ini
: Contains database connection information and Alembic settingsalembic/
: Directory containing migration scripts and environment configuration:env.py
: The Alembic environment setupscript.py.mako
: Template for generating migration filesversions/
: Directory containing migration scripts
Project Structure for Migrations
Creating a New Migration
Automatic Migration Generation
Alembic can automatically detect changes between your SQLAlchemy models and the current database schema to generate migrations:
- Make changes to your SQLAlchemy models in the
src/models/
directory - Ensure the new model is imported in the models
__init__.py
file - Run the following command to generate a migration:
This will create a new file in the alembic/versions/
directory with a format like <revision_id>_description_of_changes.py
.
Automatic Migration Process
Manual Migration Creation
For more complex changes or to insert seed data, create a manual migration:
Then edit the generated file to include your migration logic in the upgrade()
and downgrade()
functions.
Migration File Format
Each migration file follows this structure:
Migration Dependencies
Naming Convention
Following the project’s convention, you should:
- Prefix your migration file with the next sequential number
- Add a short descriptive name
- For example, if the latest migration is
010_create_upload_files.py
, name yours011_your_feature_name.py
To rename the file after generation:
Running Migrations
Upgrading the Database
To apply all pending migrations:
To upgrade to a specific revision:
To upgrade a relative number of steps:
Downgrading the Database
To downgrade to a previous revision:
To downgrade a relative number of steps:
To downgrade to the base (before any migrations):
Migration State Flow
Checking Migration Status
To see the current database revision:
To see migration history:
To see which migrations need to be applied:
Migration Examples
Creating a Table
Example Table Schema
Adding a Column
Column Addition Visualization
Modifying a Column
Adding a Foreign Key
Relationship Visualization
Inserting Seed Data
Best Practices
General Guidelines
- One migration per change: Create separate migrations for distinct changes to make them easier to understand and maintain
- Test migrations: Test both upgrade and downgrade paths before applying to production
- Be concise but descriptive: Use clear naming conventions that indicate what each migration does
- Comment your code: Add comments to complex migration logic to explain the purpose
Database Changes
- Non-destructive changes: Prefer adding over dropping where possible
- Nullable columns: When adding new columns to existing tables, make them nullable or provide a default value
- Data migrations: Separate schema changes from data migrations when possible
- Indexes: Add appropriate indexes for foreign keys and frequently queried columns
- Updated_at triggers: Add triggers for
updated_at
columns as demonstrated in the example migrations
Migration Decision Flow
SQL Execution
- Use SQLAlchemy operations: Prefer Alembic’s operation helpers (
op.*
) over raw SQL when possible - Transaction safety: Ensure your migrations are transaction-safe
- Idempotence: Make migrations idempotent where possible to avoid errors on reapplication
- Performance: Be mindful of migration performance on large tables; consider batch operations
Version Control
- Commit migrations: Always commit migration files to version control
- Do not edit applied migrations: Create new migrations rather than modifying existing ones that have been applied
Troubleshooting
Common Issues
- Autogeneration misses changes: Alembic can’t detect all types of changes. Always review auto-generated migrations.
- Migration conflicts: If multiple developers create migrations simultaneously, conflicts may occur. Coordinate migrations or adjust revision chains as needed.
- Database connection issues: Verify your database connection settings in
alembic.ini
. - SQLAlchemy model not detected: Ensure your model is imported in the models
__init__.py
file.
Troubleshooting Flow
Fixing a Failed Migration
If a migration fails midway:
- Fix the issue in the migration script
- Run
alembic upgrade head
again, or specifically target the failed migration
If you need to revert a partial migration:
- Manually fix the database state if necessary
- Mark the current revision:
alembic stamp <last_successful_revision>
- Then try upgrading again
Migration Workflow Summary
- Make changes to SQLAlchemy models
- Generate a migration with
alembic revision --autogenerate -m "description"
- Review and edit the generated migration file if necessary
- Rename the file to follow the sequential numbering convention
- Test the migration in a development environment
- Apply the migration with
alembic upgrade head
- Commit the migration file to version control
Complete Migration Lifecycle
By following this guide and examining existing migrations, you’ll be able to create and manage database migrations effectively in the Zyeta backend.
Was this page helpful?