Database Migrations
The migrations module provides SQL schema versioning with timestamped migration folders, forward and rollback scripts, database backups, and schema comparison for testing.
Enable
From the app root (where index.php and mvc.config.json live):
vendor/bin/mvc migrations:enable [--path=<app-dir>] [--folder=<module-folder>]
| Option | Default | Description |
|---|---|---|
--path |
current directory | MVC app root containing index.php and mvc.config.json. |
--folder |
Migrations |
Name of the migration module folder under the app root. |
This creates <app>/<folder>/migrations/, writes <app>/<folder>/index.php, and sets migrationsFolderPath and migrationsEnabled: true in mvc.config.json.
Disable
vendor/bin/mvc migrations:disable [--path=<app-dir>] [--remove-files] [--force]
Sets migrationsEnabled: false and clears migrationsFolderPath. By default no files are deleted.
--remove-files— delete the migration module directory from disk. Must be combined with--force.
Folder layout
graph LR
App["app/\nindex.php\nmvc.config.json"]
Mod["Migrations/\nindex.php"]
MDir["migrations/"]
M1["20260101120000/\n0001_migration.sql\n0001_migration.rollback.sql"]
M2["20260201090000/\n0001_migration.sql\n0001_migration.rollback.sql"]
App --> Mod --> MDir --> M1
MDir --> M2
Each migration is a timestamped folder (YYYYMMDDhhmmss) containing:
0001_migration.sql— forward script (applied withmvc migrations:run).0001_migration.rollback.sql— rollback script (applied to reverse the migration).
Environment variables
The migration runner reads database settings from environment variables:
| Variable | Description |
|---|---|
MIGRATIONS_DATABASE_HOST |
Database host. |
MIGRATIONS_DATABASE_NAME |
Database name. |
MIGRATIONS_DATABASE_USER |
Database user. |
MIGRATIONS_DATABASE_PASSWORD |
Database password. |
Set these before running migration commands.
Create a migration
vendor/bin/mvc migrations:create --app-path=<app-dir>
Creates a new timestamped folder under migrations/ with blank forward and rollback scripts. Edit them to add your DDL.
Override the migrations directory if needed (bypasses mvc.config.json):
vendor/bin/mvc migrations:create --path=<migrations-dir>
Run pending migrations
vendor/bin/mvc migrations:run --app-path=<app-dir>
Applies all unapplied forward scripts in chronological order. The module records which migrations have been applied.
Test a migration
Runs apply → rollback → schema comparison for a single migration folder:
vendor/bin/mvc migrations:test --app-path=<app-dir> --migration=<folder-name>
<folder-name> is the timestamped folder name (e.g. 20260101120000). The test verifies that applying and rolling back the migration leaves the schema in its original state.
Migration apply flow
flowchart TD
Start["mvc migrations:run"]
Backup["Backup database schema"]
Pending["Find unapplied migrations\n(sorted by timestamp)"]
Apply["Apply forward script\n0001_migration.sql"]
Record["Record migration as applied"]
Done["All migrations applied"]
Start --> Backup --> Pending --> Apply --> Record
Record -->|more pending| Apply
Record -->|none left| Done
Best practices
- Write rollback scripts — every forward script should have a matching rollback. This enables
migrations:testand safe production rollbacks. - One concern per migration — create a new timestamped folder for each schema change. Avoid combining unrelated DDL in one migration.
- Test before deploying — run
migrations:teston all new migrations in CI before applying to production. - Never edit applied migrations — once a migration has been applied to any environment, treat it as immutable. Create a new migration to amend it.
Related documentation
- CLI Reference — all migration command flags.
- Background Tasks — background tasks depend on migrations for the default SQL table.
- Authentication —
mvc auth:enablegenerates auth migrations.