Guide

Database Migrations

Keep database schema changes clear, ordered, and recorded with the built-in migration system.

Create a migration in the application

Migrations belong to the application, conventionally in App\Database\Migrations. Each class has a stable YYYYMMDDHHMMSS_description identifier and applies schema changes in up(Schema $schema). Once a migration has been applied, do not change its identifier.

example.php
<?php

declare(strict_types=1);

namespace App\Database\Migrations;

use Lemonade\Framework\Database\Migration\MigrationInterface;
use Lemonade\Framework\Database\Schema\Schema;

final class CreateUsersTable implements MigrationInterface
{
    public static function identifier(): string
    {
        return '20260908090000_create_users';
    }

    public function up(Schema $schema): void
    {
        $schema->create('users', static function ($table): void {
            $table->id();
            $table->string('email', 255);
            $table->string('password', 255);
        });
    }
}

Register migration classes explicitly

Register each migration as a class-string in AppServiceProvider. MigrationRegistry validates and orders the identifier without instantiating the migration. Applied migrations and status checks therefore do not need to instantiate migration classes or resolve their constructor dependencies.

example.php
<?php

declare(strict_types=1);

namespace App\Providers;

use App\Database\Migrations\CreateUsersTable;
use Lemonade\Framework\Container\ContainerInterface;
use Lemonade\Framework\Core\ServiceProviderInterface;
use Lemonade\Framework\Database\Migration\MigrationRegistry;

final class AppServiceProvider implements ServiceProviderInterface
{
    public function register(ContainerInterface $container): void
    {
        $registry = $container->get(MigrationRegistry::class);

        $registry->register(CreateUsersTable::class);
    }
}

Run migrations and inspect their status

Run pending migrations through the CLI. database:migrate:status shows applied and pending migrations, as well as identifiers stored in migration history that are no longer registered in the application.

example.php
vendor/bin/lemonade database:migrate
vendor/bin/lemonade database:migrate:status

Keep applied migration history stable

Migrations are one-way. Lemonade does not provide rollback, down(), batches, checksums, automatic filesystem discovery, or automatic DDL transactions. Available schema operations depend on the configured database driver and dialect.