Doctrine Migrations vs. Schema Update: The Right Choice for Production

Joey Masip Romeu
4 min readOct 8, 2024

--

When managing databases in Symfony applications, developers often face the challenge of keeping their database schema synchronized with their application’s data model. A common mistake many developers make — especially in the early stages of development — is relying on the doctrine:schema:update --force command to directly update the database. While this may seem convenient, especially in local development, it can lead to serious problems when running in a production environment.

In this post, I’ll explain why using Doctrine Migrations is the better approach, particularly in production environments.

Why Avoid doctrine:schema:update --force in Production?

1. Uncontrolled Schema Updates

doctrine:schema:update --force makes automatic schema changes without allowing the developer to see what exactly is being altered. This can cause unexpected changes to the database, possibly leading to data loss or schema corruption.

2. Lack of Version Control

With doctrine:schema:update --force, you have no clear history of schema changes. If you need to rollback changes or track how the database evolved over time, you're out of luck.

3. No Rollback Option

In case an update fails, there’s no built-in mechanism to revert the database schema to its previous state. This makes schema changes riskier, especially in production.

Why Doctrine Migrations Are the Better Choice

Doctrine Migrations provide a much safer and controlled way to handle database changes in any environment, but they are essential for production. Here’s why:

1. Version Control for Your Database

Doctrine Migrations allow you to create versioned migration files that describe the changes to be applied to your database. Each migration corresponds to a specific change, and these migrations can be committed to version control along with your code.

2. Predictability and Safety

With migrations, you know exactly what changes will be applied to the database. This predictability ensures you can review and test migrations before applying them to production.

3. Rollback Support

Migrations come with built-in support for rolling back changes. If something goes wrong, you can easily revert the database to a previous state.

4. Better Control in Production

Instead of applying arbitrary changes directly to the production database, you execute migrations that have been tested and reviewed. This helps minimize the risk of downtime or critical data loss.

How to Use Doctrine Migrations in Production

Let’s walk through a typical setup to manage database schema changes using Doctrine Migrations in a Symfony project. We’ll look at how to create migrations, execute them during a deployment, and rollback if needed.

Step 1: Generating a Migration

First, whenever you make changes to your data model (like adding a field to an entity), you need to generate a migration file:

bin/console doctrine:migrations:diff

This will generate a migration file in your migrations/ directory. The file will contain SQL queries that correspond to the changes in your entities.

Step 2: Reviewing the Migration

Before running the migration, always review the generated file to ensure that the changes are correct and won’t cause issues in your database. For example, here’s what a simple migration might look like:

<?php declare(strict_types=1);namespace DoctrineMigrations;use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20241002185538 extends AbstractMigration
{
public function up(Schema $schema): void
{
// Apply changes
$this->addSql('ALTER TABLE log_sync CHANGE command command VARCHAR(510) NOT NULL');
}
public function down(Schema $schema): void
{
// Revert changes
$this->addSql('ALTER TABLE log_sync CHANGE command command VARCHAR(255) NOT NULL');
}
}

Step 3: Executing the Migration in Production

Instead of running doctrine:schema:update --force in production, you should run the migration you’ve prepared and reviewed. You can execute all pending migrations like this:

bin/console doctrine:migrations:migrate --no-interaction

This will apply the latest available migration(s) to your production database safely.

Step 4: Managing Migrations During Deployments

For automated deployments, it’s important to track which migration version has been applied. You can create a script to read the migration version from a file and run the migration like so:

# Read the version from the file, replacing double backslashes with a single backslash
TARGET_VERSION=$(cat MIGRATION_VERSION)

# Executing migration for: $TARGET_VERSION"
bin/console doctrine:migrations:migrate DoctrineMigrations\\$TARGET_VERSION --no-interaction

This script ensures that only the specific version defined in MIGRATION_VERSION is executed, giving you precise control over which migration is applied during the deployment process.

The MIGRATION_VERSION file will just contain the version like so:

Version20241002185538

Example Deployment Script

Here’s a simple deployment script that could be part of your CI/CD pipeline:

# Read the target version from the migration version file
TARGET_VERSION=$(cat MIGRATION_VERSION)

# Apply the migration
bin/console doctrine:migrations:migrate DoctrineMigrations\\$TARGET_VERSION --no-interaction
bin/console cache:clear

Rolling Back Migrations

If something goes wrong in production, you can easily rollback the last applied migration. To rollback a specific migration, use

bin/console doctrine:migrations:execute --down 'DoctrineMigrations\\Version20241002185538'

This will revert the changes made by the migration.

Or you can also use the MIGRATION_VERSION file like so

TARGET_VERSION=$(cat MIGRATION_VERSION)
bin/console doctrine:migrations:migrate DoctrineMigrations\\$TARGET_VERSION --no-interaction

Conclusion

Relying on doctrine:schema:update --force may be tempting due to its simplicity, but it poses significant risks in a production environment. Using Doctrine Migrations gives you a much more controlled, predictable, and secure way of handling database schema changes, especially during deployment.

With migrations, you gain the ability to track, version, and rollback database changes, which are critical features when working in production. By implementing migrations, you ensure your application remains stable and your database is managed safely.

By following these steps and practices, you’ll have a robust database migration process that scales with your application. If you have any questions or tips from your own experiences with Doctrine Migrations, feel free to share them in the comments below!

--

--

Joey Masip Romeu
Joey Masip Romeu

Written by Joey Masip Romeu

Coder, Entrepreneur, Co-founder at SlowCode

No responses yet