Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

simonw's avatar

What order does migrate:rollback execute?

Consider the following migrations:

2019_09_27_231239_update_created_at
2019_09_13_185347_add_foreign_keys
2019_09_13_190541_add_new_column

When running php artisan migrate they go in to the migrations table in date order.

In the database they are given a batch and and ID

25       2019_09_13_185347_add_foreign_keys       14
26       2019_09_13_190541_add_new_column         14
27       2019_09_27_231239_update_created_at      14

Now when I run migrate:rollback. Would that reverse batch 14 using the ID: 27, 26, 25 or does it pull the date string from the filename and reverse it based on date order.

I ask because if someone were to add a row in to migrations manually:

...

28       2019_09_10_145426_add_indexes      14

Then would this run last, as the date is 10th Sept. Or would it run first as the ID is 28?

0 likes
10 replies
Tray2's avatar

Why would someone want to manually add a row there?

simonw's avatar

But that isn't what I am asking... The question asks about the order of migrations being rolled back. Why someone wants to add a row there is not relevant to the question or the answer, besides being used as an example.

1 like
fylzero's avatar

Rollback will execute the down method of your migrations.

If you run...

php artisan migrate:rollback --step=1

It will only rollback (aka run the down method on) your last migration. You can change the step number to rollback 1, 2, 3, whatever you want migrations.

25 likes
simonw's avatar

That is useful. And yes, it rolls-back the down methods() but still, in what order?

ID DESC, or Alpha-numeric DESC?

I only started to consider this, because it migrates forward based on alpha-numeric, or date_created. Unsure of that too.

Sinnbeck's avatar

I would suppose this could just be tested in a matter of minutes? Create 2 migrations and migrate them. Add a new one in between them date wise. Migrate again. Now rollback 1. Which one is taken? The last or the middle one

Sadly I am not near a computer at the moment so I cannot test myself

fylzero's avatar

@simonw In desc order. They rollBACK not forward. It starts with the last one migrated.

24 likes
simonw's avatar

@fylzero Thank you. I think you somewhat missed what I was asking, but I assume you mean it starts with the highest ID, and goes back from there. Which answers my question.

Just to clarify, I understand its a rollBACK, but "back" is ambiguous if there is more than one way to roll back. It is equally likely that Laravel rolls-BACK the migrations in reverse order of the date in the migration instead of using the ID. Both methods would reverse the migrations in the correct order. And this is exactly why I gave the example of manually entering a migration in to the database, because at that point, the date becomes important.

Assuming it's ID. Thanks :)

siangboon's avatar

I thought the explanation and code is clear

// We want to pull in the last batch of migrations that ran on the previous // migration operation. We'll then reverse those migrations and run each // of them "down" to reverse the last migration "operation" which ran.

/**
     * Rollback the last migration operation.
     *
     * @param  array|string $paths
     * @param  array  $options
     * @return array
     */
    public function rollback($paths = [], array $options = [])
    {
        // We want to pull in the last batch of migrations that ran on the previous
        // migration operation. We'll then reverse those migrations and run each
        // of them "down" to reverse the last migration "operation" which ran.
        $migrations = $this->getMigrationsForRollback($options);

        if (count($migrations) === 0) {
            $this->note('<info>Nothing to rollback.</info>');

            return [];
        }

        return $this->rollbackMigrations($migrations, $paths, $options);

    }


     /**
     * Get the migrations for a rollback operation.
     *
     * @param  array  $options
     * @return array
     */
    protected function getMigrationsForRollback(array $options)
    {
        if (($steps = $options['step'] ?? 0) > 0) {
            return $this->repository->getMigrations($steps);
        }

        return $this->repository->getLast();
    }

https://laravel.com/api/6.x/Illuminate/Database/Migrations/MigrationRepositoryInterface.html#method_getLast

array getLast()
Get the last migration batch.

Return Value
array
fylzero's avatar

@simonw You reeeeeally shouldn't add a row to migrations or touch the migrations table ever. That would be an incorrect thing to do.

When you create migrations through artisan and migrate normally, the ids will align to the filenames. Adding a migration manually to that table is something that should LITERALLY NEVER be done for any reason.

If you need to update a table, make a new migration... work the timeline forward. Once migrations are in production, they should not be modified, ever.

The answer is, migrations rollback in the order they are created based on the date in the filename... which very well may be subsequently based on the id... why your asking does matter a bit... because the answer to whether this is using the id or date is irrelevant as they should always be aligned.

24 likes
srinathdudi's avatar

After a quick test with two migrations below

/**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        printf("table 1 created\n");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        printf("table 1 deleted\n");
    }
/**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        printf("table 2 created\n");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        printf("table 2 deleted\n");
    }

Here is the result of migrate command

php artisan migrate
Migrating: 2019_11_23_235642_test_migration_1
table 1 created
Migrated:  2019_11_23_235642_test_migration_1
Migrating: 2019_11_23_235704_test_migration_2
table 2 created
Migrated:  2019_11_23_235704_test_migration_2

Here is the result of rollback command

php artisan migrate:rollback
Rolling back: 2019_11_23_235704_test_migration_2
table 2 deleted
Rolled back:  2019_11_23_235704_test_migration_2
Rolling back: 2019_11_23_235642_test_migration_1
table 1 deleted
Rolled back:  2019_11_23_235642_test_migration_1

So it is clear that it will rollback the latest migration in the batch first. This is obviously the right way to rollback. Because the second migration might have something which is dependent on the first migration. So it is better to rollback the latest migration first.

For example the first migration may create customers table and the second migration will create orders table with a foreign key of customer_id which references the customers table. In this case, Rolling back the first migration will fail because the table has a column which is referenced on the orders table.

1 like

Please or to participate in this conversation.