Skip to content

Doctrine Migrations — Complete Guide to Database Schema Versioning

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Doctrine Migrations. We cover key concepts, practical examples, and best practices to help you master this topic.

Doctrine Migrations provide version control for database schemas, allowing teams to generate Migration classes from entity changes and apply them across environments.

What You'll Learn

By the end of this tutorial, you'll set up Doctrine Migrations, generate migrations from entity diffs, write custom SQL migrations, manage versions, and deploy safely.

Why Migrations Matter

Database schema changes must be versioned, reversible, and consistently applied across development, staging, and production. Migrations ensure all environments stay in sync with code.

Real-World Use

A development team adds a new entity for Ratings. Running vendor/bin/doctrine migrations:diff generates the migration. After code review, the migration is applied on staging and production.

Migrations Path

flowchart LR
  A[Doctrine ORM] --> B[Doctrine Migrations]
  B --> C[Generate Diff]
  B --> D[Apply Migration]
  B --> E[Rollback]
  B --> F[Version Control]
  B --> G{You Are Here}
  style G fill:#f90,color:#fff

Setup and Configuration

Install and configure Doctrine Migrations.

<?php
// config/migrations.php
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Configuration\Migration\PhpFile;
use Doctrine\Migrations\Configuration\EntityManager\ExistingEntityManager;
$config = new PhpFile("migrations.php");
return DependencyFactory::fromEntityManager($config, new ExistingEntityManager($entityManager));
# migrations.php
migrations_paths:
  'DoctrineMigrations': 'lib/DoctrineMigrations'
default_environment: 'dev'
table_name: 'doctrine_migration_versions'
organize_migrations: BY_YEAR_AND_MONTH

Generating Migrations

Auto-generate migrations from entity changes.

vendor/bin/doctrine migrations:diff

Generated Migration

The generated migration class.

<?php
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260628120000 extends AbstractMigration {
    public function getDescription(): string {
        return "Create ratings table";
    }
    public function up(Schema $schema): void {
        $this->addSql("CREATE TABLE ratings (
            id INT AUTO_INCREMENT NOT NULL,
            product_id INT NOT NULL,
            user_id INT NOT NULL,
            score INT NOT NULL,
            created_at DATETIME NOT NULL,
            PRIMARY KEY(id)
        ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
        $this->addSql("ALTER TABLE ratings ADD CONSTRAINT FK_RATINGS_PRODUCT FOREIGN KEY (product_id) REFERENCES products(id)");
    }
    public function down(Schema $schema): void {
        $this->addSql("DROP TABLE ratings");
    }
}

Custom SQL Migrations

Write migrations with custom SQL for complex changes.

<?php
final class Version20260628130000 extends AbstractMigration {
    public function up(Schema $schema): void {
        $this->addSql("UPDATE products SET price = price * 1.1 WHERE category_id = (SELECT id FROM categories WHERE name = 'premium')");
        $this->addSql("INSERT INTO audit_log (action, table_name) VALUES ('price_update', 'products')");
    }
    public function down(Schema $schema): void {
        $this->addSql("UPDATE products SET price = price / 1.1 WHERE category_id = (SELECT id FROM categories WHERE name = 'premium')");
    }
}

Common Mistakes

1. Editing Applied Migrations

Never edit a migration that has been applied to production. Create a new migration for changes.

2. Not Testing Migrations Down

Always test the down() method to ensure rollbacks work correctly.

3. Large Migrations

Break large schema changes into multiple migrations. Each migration should be atomic.

4. Ignoring Migration Dependencies

Use getMigrationDependencies() when migrations must run in a specific order.

5. Not Version-Controlling Migrations

Migrations must be in version control. They are code and should be reviewed.

Practice Questions

1. How do you generate a migration from entity changes?

Run vendor/bin/doctrine migrations:diff to compare the schema with entities.

2. What is the down() method for?

Reverse the changes made in up(), enabling rollback.

3. How do you apply pending migrations?

Run vendor/bin/doctrine migrations:migrate.

4. Can you write raw SQL in migrations?

Yes. Use $this->addSql() in the up() and down() methods.

5. Challenge: Create a migration that adds a column with default data.

<?php
final class Version20260628140000 extends AbstractMigration {
    public function up(Schema $schema): void {
        $this->addSql("ALTER TABLE users ADD COLUMN timezone VARCHAR(50) NOT NULL DEFAULT 'UTC'");
        $this->addSql("UPDATE users SET timezone = 'America/New_York' WHERE region = 'us_east'");
    }
    public function down(Schema $schema): void {
        $this->addSql("ALTER TABLE users DROP COLUMN timezone");
    }
}

FAQ

Should migrations be in version control?

Yes. Migrations are code and must be tracked in version control with the entities they correspond to.

Can I have multiple migration directories?

Yes. Configure multiple paths in the migrations configuration.

How do I migrate a specific version?

Run vendor/bin/doctrine migrations:execute --up VERSION for a specific version.

What happens if a migration fails?

The migration is marked as not applied. Fix the migration and re-run.

Can I preview SQL before applying?

Yes. Run vendor/bin/doctrine migrations:up-to-date --dry-run to see pending SQL.

Mini Project: Migration Workflow

Set up a complete migration workflow for a team project.

# Generate migration from entity changes
vendor/bin/doctrine migrations:diff
# Review the generated migration file
code lib/DoctrineMigrations/Version20260628120000.php
# Apply in development
vendor/bin/doctrine migrations:migrate
# Commit both entity changes and migration
git add src/Entity/Rating.php lib/DoctrineMigrations/Version20260628120000.php
git commit -m "Add Rating entity and migration"
# Deploy on production
git pull && vendor/bin/doctrine migrations:migrate --no-interaction

What's Next

Doctrine DQL Doctrine Entities Doctrine Relations

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro