Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Creating and Applying Migrations

Creating and Applying Migrations

~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

The Project entity from chapter 19 only exists as PHP code so far – the database still knows NOTHING of a project table. Migrations close this gap in a TRACEABLE and VERSIONED way.

Why migrations instead of a direct schema update?

Doctrine offers TWO ways to bring the database schema in line with the entities – both produce the same result, but with one decisive difference:

ApproachProperties
doctrine:schema:update --forceChanges the database IMMEDIATELY and DIRECTLY, with NO record – fast for local experimentation, but NOT traceable and NOT reproducible on other environments.
Migrations (make:migration)Generates a PHP file with explicit SQL for UP (apply) and DOWN (revert) – versioned, traceable in the Git repository, runs IDENTICALLY on every environment.

Achtung: doctrine:schema:update --force is meant ONLY for local development/prototyping. For ANY application running in production (i.e. practically every real application), migrations are the only sensible way – they let you reproduce the schema on the production server EXACTLY as it evolved locally.

Creating a migration

php bin/console make:migration

Doctrine compares the CURRENT entity definitions with the CURRENT database schema and automatically generates the SQL needed for the difference:

migrations/Version20260806120000.php
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20260806120000 extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        $this->addSql('CREATE TABLE project (
            id SERIAL NOT NULL,
            name VARCHAR(255) NOT NULL,
            description TEXT DEFAULT NULL,
            created_at TIMESTAMP(0) NOT NULL,
            PRIMARY KEY(id)
        )');
    }

    public function down(Schema $schema): void
    {
        $this->addSql('DROP TABLE project');
    }
}

up() APPLIES the change, down() REVERTS it – both should ALWAYS match each other, so a migration can be rolled back cleanly in an emergency.

Applying the migration

php bin/console doctrine:migrations:migrate

Asks for confirmation (skipped with -n, useful for automated deployments in chapter 48). Doctrine runs ALL not-yet-applied migrations in chronological order and records the state in an internal doctrine_migration_versions table.

Checking the current migration status

php bin/console doctrine:migrations:status

Reverting a migration

php bin/console doctrine:migrations:migrate prev

Runs down() of the MOST RECENTLY applied migration – useful when a new migration turns out to have an issue, BEFORE it goes to production.

The standard workflow from now on

  1. Create or change an entity (as in chapter 19).
  2. php bin/console make:migration – Doctrine generates the SQL automatically.
  3. READ THROUGH the generated migration file – Doctrine is usually reliable, but especially with more complex changes (e.g. renames), a manual check pays off.
  4. php bin/console doctrine:migrations:migrate – apply it.
  5. Commit the migration AND the entity change TOGETHER – they belong together inseparably.

Tipp: This five-step workflow accompanies us through the ENTIRE rest of block 4 – every new entity or relationship follows exactly this pattern.