Database Migrations¶
CKAN extensions manage database schema changes using Alembic. This ensures database schema updates are tracked, version-controlled, and run cleanly across dev, staging, and production environments.
Migration Layout¶
Migration folder with all required files will be automatically created by CLI
ckan generate migration -p myextension when you create the first migration for plugin.
ckanext-myextension/
├── ckanext/
│ └── myextension/
│ ├── plugin.py
│ └── migration/
│ └── myextension/ # Name of your extension
│ ├── alembic.ini
│ ├── env.py
│ ├── script.py.mako
│ └── versions/ # Individual migration files
Migration Version Table Isolation¶
Since your extension shares the database with CKAN core and other extensions,
it must isolate its migration state. To achieve it, env.py, sets custom
version table name. You don't need to change any code, it's autogenerated
alongside with the first migration for the plugin.
For every plugin with migrations, there will be a separate table
PLUGIN_alembic_version in DB. Do not delete this table, as alembic uses it to
track the current state of migrations.
name = os.path.basename(os.path.dirname(__file__))
# Offline migration configuration
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
version_table=f"{name}_alembic_version", # e.g., 'myextension_alembic_version'
)
Generating Migrations¶
To generate a new database migration file for your extension, use the ckan generate migration command:
-p(or--plugin): The name of your plugin (as registered in your plugin entry points, e.g.myplugin).-m(or--message): A brief description of the schema changes, which becomes part of the generated filename.
The command creates a new Python migration script inside your extension's migration/<plugin_name>/versions/ directory.
Automatic Migration Generation¶
CKAN's migration generator supports the --autogenerate flag. This option directs Alembic to compare the metadata defined in your Python models (specifically target_metadata inside env.py) with your active database schema, and automatically output the corresponding upgrade/downgrade code:
Review Autogenerated Code
Always open and inspect the generated file under
migration/<plugin_name>/versions/ before running it. Since multiple
extensions and CKAN core share the same database, --autogenerate can
sometimes falsely detect tables belonging to other extensions as "deleted" or
"modified". Ensure the upgrade() and downgrade() blocks strictly target
your own extension's tables and columns.
Note
If --autogenerate does not detects your model, most likely it happens because
your model was never registered inside SQLAlchemy's registry. Try importing the
model into plugin.py of the extension before running the command. Once
migration is created, you can remove this unused import.
Running Migrations¶
You can manage and execute migrations using the ckan db CLI tool:
Check Pending Migrations¶
To see if there are any database migrations that have not yet been run on the current database instance:
Run Migrations¶
To execute all pending migrations and bring your database schema up to the latest revision:
To upgrade only the database migrations for a specific plugin:
In test environments, migrations are automatically run during test setup via test fixtures.
Tip
You can also revert migrations. The basic command is:
It reverts all migrations of the plugin.
When you have multiple migrations, you probably want to revert/apply only the
last migration, polishing its code. To do it, add -v -1 argument to the
command. The number after -v/--version option specifies number of
migrations affected by the command. The number is negative, as we are moving
backward. When working with db upgrade you can also specify the number of
applied migrations, but there you'd use positive numbers.