Featured image of post 3 Laravel Migration Pitfalls and How to Fix Them

3 Laravel Migration Pitfalls and How to Fix Them

Avoid 3 migration rollback mistakes: mixing add/drop in one closure, dropping index and column together, and multiple dropColumn calls. Catch them with SQLite.

I recently hit several pitfalls when using migration:rollback. Here are the common mistakes and how to catch them early with tests.

Common Mistakes

Adding and dropping columns in the same closure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Bad
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('old_column');
    $table->string('new_column');
});

// Good — split into two closures
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('old_column');
});

Schema::table('users', function (Blueprint $table) {
    $table->string('new_column');
});

Dropping an index and column at the same time

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Bad
Schema::table('users', function (Blueprint $table) {
    $table->dropIndex('users_old_column_index');
    $table->dropColumn('old_column');
});

// Good — drop the index first, then the column
Schema::table('users', function (Blueprint $table) {
    $table->dropIndex('users_old_column_index');
});

Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('old_column');
});

Dropping multiple columns must be in a single call

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Bad
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('old_column');
    $table->dropColumn('old_column2');
});

// Good
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('old_column', 'old_column2');
});

How to Automatically Validate Migrations

Running migration:rollback on a production database to test is too risky. A safer approach is to use PHPUnit + SQLite in-memory.

1. Configure phpunit.xml

Add these two lines in the <php> block:

1
2
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>

2. Write a test

It doesn’t need to be complex – just make sure the migration runs without errors:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
namespace Tests\Feature;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase;

class MigrationTest extends TestCase
{
    use DatabaseMigrations;

    public function testMigrationRunsSuccessfully()
    {
        $this->assertTrue(true);
    }
}

Run vendor/bin/phpunit. If any migration has a problem, it will fail immediately. This way you can catch broken migrations right away every time you make changes.