This plugin provides commands to Kirby CLI for simple migrations.
Use cases are database migrations for your SQL database, migrating content or creating pages when deploying your Kirby page. See the examples section for more details.
You can also create migrations for your own plugins. See the Migrations for Plugins section for more details.
This plugin uses the Kirby CLI to run migrations. Either use it via composer (this plugin will install it for you) or install it globally.
# not required, but will install the CLI globally
composer global require getkirby/cli
If you installed it globally, you can run the migrations via kirby migrations:apply
otherwise
use ./vendor/bin/kirby migrations:apply
. In the following, we will assume you’re using it via composer.
This plugin provides the following configuration options:
thathoff.migrations.dir
: The directory where the migrations are stored. Defaults to amigrations
folder inside the Kirbysite
directory.thathoff.migrations.stateFile
: The file where the state of the migrations is stored. Defaults to a.migrations
file inside themigrations
directory.
This will create a new migration file in the migrations
directory.
./vendor/bin/kirby migrations:create <name>
This will apply all pending migrations.
When using the -f
or --force
flag, it will apply the migrations without
asking for confirmation (eg. for CI/CD pipelines).
./vendor/bin/kirby migrations:apply [-f|--force]
This will show the status of the migrations.
./vendor/bin/kirby migrations:status
This will rollback the last batch of migrations.
When using the -f
or --force
flag, it will rollback the migrations without asking for confirmation.
./vendor/bin/kirby migrations:rollback [-f|--force]
Plugins can also have their own migrations. To support migrations in your plugin, you need to create a migrations
folder in your plugin's root directory and enable migrations in your plugin's index.php
file by setting the
migrations
option to true
.
use Kirby\Cms\App as Kirby;
Kirby::plugin('example/test', [
'migrations' => true,
]);
To use a different path, you can set the migrations
option to the path to the migrations directory:
use Kirby\Cms\App as Kirby;
Kirby::plugin('example/test', [
'migrations' => __DIR__ . '/classes/migrations',
]);
After this, you can create migrations for your plugin by using the migrations:create
command and specifying the
plugin ID (in the example above it’s example/test
) as the second argument.
It’s recommended to prefix your migration names with your plugins name to avoid conflicts with other plugins as all migrations are created in the same namespace.
./vendor/bin/kirby migrations:create <name> <plugin-id>
All other commands will automatically detect the plugin migrations and apply them accordingly.
All database examples assume you have a database configured in your config.php
file.
./vendor/bin/kirby migrations:create InitDb
<?php
namespace Thathoff\KirbyMigrations;
use Kirby\Database\Db;
class Migration20250524144726InitDb extends Migration
{
public function up(): void
{
$result = Db::execute("CREATE TABLE `my_table` (
id int NOT NULL,
test varchar(255) NOT NULL,
PRIMARY KEY (id)
)");
if (!$result) throw Db::lastError();
}
public function down(): void
{
$result = Db::execute("DROP TABLE `my_table`");
if (!$result) throw Db::lastError();
}
}
./vendor/bin/kirby migrations:create AddNameToMyTable
<?php
namespace Thathoff\KirbyMigrations;
use Kirby\Database\Db;
class Migration20250524150432AddNameToMyTable extends Migration
{
public function up(): void
{
$result = Db::execute("ALTER TABLE `my_table` ADD COLUMN `name` varchar(255) NOT NULL");
if (!$result) throw Db::lastError();
}
public function down(): void
{
$result = Db::execute("ALTER TABLE `my_table` DROP COLUMN `name`");
if (!$result) throw Db::lastError();
}
}
This is pretty handy when you need to create pages that should not be created manually (eg. container pages) and only should exist once.
./vendor/bin/kirby migrations:create CreatePage
<?php
namespace Thathoff\KirbyMigrations;
class Migration20250524150757CreatePage extends Migration
{
public function up(): void
{
$content = [
'title' => 'An interesting title',
'text' => 'Some great content here…'
];
// make sure we are allowed to create the page
$this->kirby->impersonate('kirby');
$this->kirby->site()->createChild([
'content' => $content,
'slug' => 'created-by-migration',
'template' => 'default',
'isDraft' => false,
]);
}
public function down(): void
{
// make sure we are allowed to delete the page
$this->kirby->impersonate('kirby');
$this->kirby->site()->find('created-by-migration')?->delete();
}
}
Maintained and developed by Markus Denhoff and Contributors.
Supported by reinorange GmbH.