Migration System

How fastappkit's migration system works internally.

Migration Architecture

fastappkit uses a unified migration runner that coordinates database schema management across core, internal apps, and external apps.

┌─────────────────────────────────────────────┐
│         Unified Migration Runner            │
└─────────────────────────────────────────────┘
   ┌──────────┴──────────┐
   ▼                     ▼
CORE MIGRATIONS     APP MIGRATIONS
                     (per app)
                     internal → external
                     shared    → isolated
   │                     │
   └──────────┬──────────┘
    ┌───────────────────────┐
    │ Alembic Multi-Env API │
    └───────────────────────┘
         DATABASE

Version Tables

  • Core & Internal Apps: Use shared alembic_version table
  • External Apps: Use per-app tables (alembic_version_<appname>)

This isolation ensures external apps don't conflict with each other or with core/internal migrations.

Migration Execution Flow

For Core + Internal Apps

  1. Load Migration Directory
  2. Location: core/db/migrations/
  3. Shared by core and all internal apps

  4. Build Revision Graph

  5. Scan versions/ directory for migration files
  6. Parse revision IDs and dependencies
  7. Determine head revision

  8. Check Database State

  9. Connect to database
  10. Check alembic_version table
  11. Read current revision

  12. Determine Upgrade Path

  13. Compare current revision with head
  14. Build list of migrations to apply (in order)

  15. Execute Migrations

  16. For each migration: execute upgrade(), update version table, commit

For External App Upgrade

  1. App Resolution & Validation
  2. Resolve app from fastappkit.toml
  3. Load manifest
  4. Validate app exists and is external type
  5. Get migrations_path from manifest

  6. Build Alembic Config

  7. Set script_location = external app's migrations directory
  8. Set version_table = alembic_version_<appname>
  9. Set sqlalchemy.url = core project's DATABASE_URL (from settings)
  10. Set config_file_name = None (don't read external app's alembic.ini)

  11. Load Migration Scripts

  12. Create ScriptDirectory from migration folder
  13. Scan migrations/versions/ for .py files
  14. Parse revision IDs and build revision graph
  15. Determine head revision

  16. Check Database State

  17. Connect to core project's database
  18. Check if alembic_version_<appname> table exists
  19. Read current revision (or None if first time)

  20. Determine Upgrade Path

  21. Compare current revision with head
  22. Build list of migrations to apply (in order)

  23. Execute Migrations

  24. For each migration: execute upgrade(), update version table, commit
  25. Create version table if it doesn't exist (first migration)

Migration Ordering

Migrations run in this order:

  1. Core (always first)
  2. Internal apps (order from fastappkit.toml or [tool.fastappkit.migration.order])
  3. External apps (order from fastappkit.toml)

You can override internal app order in config:

[tool.fastappkit.migration]
order = ["core", "auth", "blog"]

Note: "core" is a special value (always first). Only affects internal apps.

Autogenerate Behavior

Internal Apps

Autogenerate sees:

  • All internal app models
  • All core models
  • Cross-app relationships

Good for: Teams working on shared schema.

External Apps

Autogenerate sees:

  • Only that app's own models
  • No internal app models
  • No other external apps' models
  • No core models

If an external app tries to import foreign models → validation error.

Edge Cases

Database Has Revision But File Missing

Error: Can't locate revision identified by '...'

Cause: Database has revision stored but migration file doesn't exist.

Solution: - Check migration files exist - Restore missing migration file - Or reset version table (if safe)

Migration File References Non-Existent down_revision

Error: Migration dependency chain broken

Solution: - Review migration files - Fix down_revision references - Ensure migration chain is complete

Empty Migration Directory

Problem: External app has no migrations

Solution: - Create initial migration: alembic revision --autogenerate -m "initial" - Ensure migrations/versions/ directory exists

Learn More