Running one specific Laravel migration (single file)
Asked Answered
T

16

101

I have 5 migrations in my project. I only want to run one of these migrations. Is it possible to pass the name of a single file to the php artisan migrate command?

Teutonic answered 30/9, 2013 at 19:27 Comment(1)
I also have the same use case. There should be such an option. I need to run a migration, then a large etl script, then run the second half of the migration. It makes no sense that the second file should not be in my code base, until the etl script is run.Cherilyncherilynn
C
58

Looks like you're doing it wrong.

Migrations were made to be executed by Laravel one by one, in the exact order they were created, so it can keep track of execution and order of execution. That way Laravel will be able to SAFELY rollback a batch of migrations, without risking breaking your database.

Giving the user the power to execute them manually, make it impossible to know (for sure) how to rollback changes in your database.

If your really need to execute something in your database, you better create a DDL script and manually execute it on your webserver.

Or just create a new migration and execute it using artisan.

EDIT:

If you need to run it first, you need to create it first.

If you just need to reorder them, rename the file to be the first. Migrations are created with a timestemp:

2013_01_20_221554_table

To create a new migration before this one you can name it

2013_01_19_221554_myFirstMigration
Crenulation answered 30/9, 2013 at 19:45 Comment(16)
YEs, so clear whta you say, but at the end of your comment I see : "Or just create a new migration and execute it using artisan." I created a new migration and I would like to run it. If I do : artisan migrate, this comman will run all my migration not the new one I created.Teutonic
If you need to run it FIRST, you needed to create it first. Migrations are created with a timestemp on name (2013_01_20_221554_table), just rename yours to be the first one.Crenulation
Edited to better answer.Crenulation
I am not seeking to reorder my migrations. I create five migrations at the begining of the project. Weeks after, I see I need a new table, so I create a new migration. I want to run this to add the new table and its structure. I don't understand why I should re-run migrations I already excecuted and not juste the new one I created ?Teutonic
As I said, Laravel keeps track of your migrations, if it's reruning any of them is because a rollback (or reset) was executed on it, or something bad happened with migrations table.Crenulation
AH ! Great ! This remark .if it's reruning any of them is because a rollback (or reset)Teutonic
Thank you Antonio. I am going to backup my bdd ( instead, lol) and do it.Teutonic
If you migrate the database, then add new migrations, simply run the artisan migrate command again. It will migrate all of the non migrated migrations left in the order they were created.Bailey
@AntonioCarlosRibeiro how does laravel keep track of the migrations that already have been executed? does it store it in a migrations table in the db?Gillis
Yes, exactly, there's a migrations file for this purpose.Crenulation
Anyway, I think run specific migrations maybe helpful, especially if migration includes several related tables (with foreign keys and pivot tables), in such case you need to drop tables in proper order. I create base migrations like catalog_layer, office_layer etc which includes all tables needed for single part of app functionality and later add migrations which improve some tables/layers if needed. Maybe this is wrong approach, but all layer stuff for some feature in single file and have proper drop order, which useful when you change and seed again and again (testing/improvements/changes).Partlow
I agree - when developing I want my migrations to be just right. So when I run them in production they work flawlessly. Sometimes (in development) I roll back to the start - alter a migration and go again. But when I migrate, it migrates all - I would prefer the option to still run one at a time, still in sequence and migrate one at a time so that I can rollback one at a time also.Clyburn
-1 because of "Looks like you're doing it wrong". IMHO the Laravel is doing it wrong. Development <> Production. The two environments demand different types of guarantees and safety measures and it is completely legitimate if they follow different disciplines. Development requires flexibility above all and it just might happen that a developer needs to tweak the migration mechanism to his needs. I am myself missing this flexibility dearly and resort to direct database manipulation in order to get what I want which would NEVER happen in production but often enough in development.Mucoid
@ashy_32bit I disagree with you, because Laravel is not doing anything wrong. The rule is "Never edit migrations that were executed in production". But you can edit local migrations in any way you see fit.Charactery
Maybe I am missing something here, but one case where executing a single migration can be very useful is in testing. If you want to run some tests after a big migration then you will likely first need some tables and stuff in the testing db so you can populate it. Then you want to run your big migration and make sure everything looks okay in the tests. As far as I can tell this requires some hacky approach in Laravel like moving migrations in and out of the migration dir or using the finicky --path option.Flagstad
Regardless of renaming the file, it did not work for me when creating the migration file manually. It did work when I did it through php artisan make:migration migration-name-here. I'm running Laravel 5.7Doyon
S
64

You can put migrations in more folders and run something like:

php artisan migrate --path=/app/database/migrations/my_migrations
Sufi answered 27/2, 2016 at 9:59 Comment(2)
To me this looks like a better solution than editing migration timestamps although it also worksChun
As pointed by @virajs0ni in the reply here: #47152386, use migrate:refresh, though be warned that it will recreate tables from scratchLitchi
C
58

Looks like you're doing it wrong.

Migrations were made to be executed by Laravel one by one, in the exact order they were created, so it can keep track of execution and order of execution. That way Laravel will be able to SAFELY rollback a batch of migrations, without risking breaking your database.

Giving the user the power to execute them manually, make it impossible to know (for sure) how to rollback changes in your database.

If your really need to execute something in your database, you better create a DDL script and manually execute it on your webserver.

Or just create a new migration and execute it using artisan.

EDIT:

If you need to run it first, you need to create it first.

If you just need to reorder them, rename the file to be the first. Migrations are created with a timestemp:

2013_01_20_221554_table

To create a new migration before this one you can name it

2013_01_19_221554_myFirstMigration
Crenulation answered 30/9, 2013 at 19:45 Comment(16)
YEs, so clear whta you say, but at the end of your comment I see : "Or just create a new migration and execute it using artisan." I created a new migration and I would like to run it. If I do : artisan migrate, this comman will run all my migration not the new one I created.Teutonic
If you need to run it FIRST, you needed to create it first. Migrations are created with a timestemp on name (2013_01_20_221554_table), just rename yours to be the first one.Crenulation
Edited to better answer.Crenulation
I am not seeking to reorder my migrations. I create five migrations at the begining of the project. Weeks after, I see I need a new table, so I create a new migration. I want to run this to add the new table and its structure. I don't understand why I should re-run migrations I already excecuted and not juste the new one I created ?Teutonic
As I said, Laravel keeps track of your migrations, if it's reruning any of them is because a rollback (or reset) was executed on it, or something bad happened with migrations table.Crenulation
AH ! Great ! This remark .if it's reruning any of them is because a rollback (or reset)Teutonic
Thank you Antonio. I am going to backup my bdd ( instead, lol) and do it.Teutonic
If you migrate the database, then add new migrations, simply run the artisan migrate command again. It will migrate all of the non migrated migrations left in the order they were created.Bailey
@AntonioCarlosRibeiro how does laravel keep track of the migrations that already have been executed? does it store it in a migrations table in the db?Gillis
Yes, exactly, there's a migrations file for this purpose.Crenulation
Anyway, I think run specific migrations maybe helpful, especially if migration includes several related tables (with foreign keys and pivot tables), in such case you need to drop tables in proper order. I create base migrations like catalog_layer, office_layer etc which includes all tables needed for single part of app functionality and later add migrations which improve some tables/layers if needed. Maybe this is wrong approach, but all layer stuff for some feature in single file and have proper drop order, which useful when you change and seed again and again (testing/improvements/changes).Partlow
I agree - when developing I want my migrations to be just right. So when I run them in production they work flawlessly. Sometimes (in development) I roll back to the start - alter a migration and go again. But when I migrate, it migrates all - I would prefer the option to still run one at a time, still in sequence and migrate one at a time so that I can rollback one at a time also.Clyburn
-1 because of "Looks like you're doing it wrong". IMHO the Laravel is doing it wrong. Development <> Production. The two environments demand different types of guarantees and safety measures and it is completely legitimate if they follow different disciplines. Development requires flexibility above all and it just might happen that a developer needs to tweak the migration mechanism to his needs. I am myself missing this flexibility dearly and resort to direct database manipulation in order to get what I want which would NEVER happen in production but often enough in development.Mucoid
@ashy_32bit I disagree with you, because Laravel is not doing anything wrong. The rule is "Never edit migrations that were executed in production". But you can edit local migrations in any way you see fit.Charactery
Maybe I am missing something here, but one case where executing a single migration can be very useful is in testing. If you want to run some tests after a big migration then you will likely first need some tables and stuff in the testing db so you can populate it. Then you want to run your big migration and make sure everything looks okay in the tests. As far as I can tell this requires some hacky approach in Laravel like moving migrations in and out of the migration dir or using the finicky --path option.Flagstad
Regardless of renaming the file, it did not work for me when creating the migration file manually. It did work when I did it through php artisan make:migration migration-name-here. I'm running Laravel 5.7Doyon
Q
43

Just move the already run migrations out of the app/config/database/migrations/ folder . Then run the command php artisan migrate . Worked like a charm for me .

Qr answered 4/2, 2014 at 16:21 Comment(2)
tried this and it is a good one but I don't if I will encounter a problem when I rollback thoughHaman
yes @Diamond, like for plugin based module when need to uninstall then it might be a big problem to roll back..Kronstadt
D
27

A nice little snippet to ease any fears when running Laravel 4 migrations php artisan migrate --pretend . This will only output the SQL that would have been run if you ran the actual migration.

It sounds like your initial 4 migrations have already been run. I would guess that when you php artisan migrate it will only run the new, recent migration.

Word of advice: makes sure all of your up() and down() work how you expect them to. I like to run up(), down(), up() when I run my migrations, just to test them. It would be awful for you to get 5-6 migrations in and realize you can't roll them back without hassle, because you didn't match the down() with the up() 100% percent.

Just my two cents! Hope the --pretend helps.

Distort answered 24/12, 2013 at 16:1 Comment(2)
The --pretend has a drawback. In both up and down methods, if you query the database, it will return no records.Celt
@BinarWeb I've run into this issue. For others here, if you need to query the database via select to get a foreign key for an insert into another table or something, no results will be returned. If you were trying to return an object, eg. a User, and you were trying to update a field on it, you might get an error like Creating default object from empty value. All queries in a migration are run in something like a transaction that's rolled back, although maybe not literally.Brok
T
18

The only way to re run a migrattion is a dirty one. You need to open your database and delete the line in the migrations table that represents your migration.

Then run php artisan migrate again.

Trafficator answered 4/2, 2014 at 15:33 Comment(4)
Also you can set the "batch" field - laravel runs (and rolls back) migrations one batch at a time, so you can just change the batch number to allow rolling back a single migration.Carpous
we can not do this to migrations table This table does not contain a unique column. Grid edit, checkbox, Edit, Copy and Delete features are not available.Depew
Well i say it may depends on the db engine you use. In my case it worked well that way. As long as you can execute SQL commands manually you can do a select then a delete.Trafficator
In most cases, yes. But it depends on the complexity of the migration you want to re-do. If it's adding a table and no other migrations rely on altering the same table, yes, just drop the table manually, delete the row in the migrations table corresponding to the migration you want to run. This is how I use the migration feature while designing the table. Since it's the last/latest/newest migration, it's a snap to do it this way and works perfectly.Elenaelenchus
T
11

If you want to run(single file) migration in Laravel you would do the following:

php artisan migrate --path=/database/migrations/migrations_file_name

eg.

C:\xampp\htdocs\laravelv3s>php artisan migrate --path=/database/migrations/2020_02_14_102647_create_blogs_table.php
Trilbie answered 14/2, 2020 at 10:45 Comment(3)
This work for me remove the dash in beginning of path php artisan migrate --path=database/migrations/migrations_file_nameEncroach
I run php artisan migrate --path=/myblog/migrations/2022_03_03_104000_create_posts_table.php, where myblog is the database name. I get a Nothing to migrate. message from the VS Code terminal. It's a Laravel 8 app. What am I doing wrong?Cavicorn
@RazvanZamfir the database here is the directory in the project root. It's not your application's database.Foursome
D
8

You can create a separate directory for your migrations from your terminal as follows:

mkdir /database/migrations/my_migrations

And then move the specific migration you want to run to that directory and run this command:

php artisan migrate --path=/database/migrations/my_migrations

Hope this helps!

Dovap answered 4/9, 2017 at 17:19 Comment(0)
W
5

You can use below solution:

  1. create your migration.
  2. check your migration status like: php artisan migrate:status.
  3. copy the full name of new migration and do this like: php artisan migrate:rollback --path:2018_07_13_070910_table_tests.
  4. and then do this php artisan migrate.

finally, you migrate specific table. Goodluck.

Weaponeer answered 13/7, 2019 at 7:24 Comment(0)
H
4

I gave this answer on another post, but you can do this: run artisan migrate to run all the migrations, then the following SQL commands to update the migrations table, making it look like the migrations were run one at a time:

SET @a = 0;  
UPDATE migrations SET batch = @a:=@a+1;

That will change the batch column to 1, 2, 3, 4 .. etc. Add a WHERE batch>=... condition on there (and update the initial value of @a) if you only want to affect certain migrations.

After this, you can artisan migrate:rollback as much as is required, and it'll step through the migrations one at a time.

Hurried answered 27/8, 2015 at 16:23 Comment(1)
This is by far the best solution. I think the query above is a bit overkill, but the underlying principle is fantastic, and incredibly simple. To keep effort minimal, just bump the migrations table record you want to run alone to the "top" ie. alter its batch column number to be the highest in the table. Roll it back (especially if you want to test your down() method) and re-run php artisan migrate.Brok
A
2

If you want to run your latest migration file you would do the following:

php artisan migrate

You can also revert back to before you added the migration with:

php artisan migrate: rollback
Argonaut answered 18/12, 2015 at 16:25 Comment(0)
B
2

There is one easy way I know to do this can only be available for you on just local host

  1. Modify your migration file as needed
  2. open your phpMyAdmin or whatever you use to see your database table
  3. find the desired table and drop it
  4. find migrations table and open it
  5. in this table under migration field find your desired table name and delete its row
  6. finally run the command php artisan migrate from your command line or terminal. this will only migrate that tables which not exists in the migrations table in database.

This way is completely safe and will not make any errors or problems while it looks like un-professional way but it still works perfectly.

good luck

Busybody answered 25/7, 2017 at 13:22 Comment(0)
B
1

I have same problem. Copy table creation codes in first migration file something like below:

  public function up()
    {
        Schema::create('posts', function(Blueprint $table){
            $table->increments('id');
            // Other columns...
            $table->timestamps();
        });
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            // Other columns...
            $table->softDeletes()->nullable();
        });
    }

Also you can change(decrease) batch column number in migrations table ;)

And then run php artisan migrate.

Brough answered 13/10, 2016 at 17:33 Comment(0)
I
0

If it's just for testing purposes, this is how i do it:

For my case, i have several migrations, one of them contains App-Settings.

While I'm testing the App and not all of the migrations are already setup i simply move them into a new folder "future". This folde won't be touched by artisan and it will only execute the migration you want.

Dirty workaround, but it works...

Isagoge answered 5/7, 2015 at 9:13 Comment(0)
T
0

Throw an exception in a migration, if you don't want to apply it, and it would stop the whole process of migration.

Using this approach you can split your bunch of migrations into steps.

Triglyceride answered 26/4, 2017 at 5:49 Comment(0)
B
0

For anybody still interested in this, Laravel 5 update: Laravel has implemented the option to run one migration file at a time (in version 5.7).

You can now run this: php artisan migrate --path=/database/migrations/my_migration.php (as answered here)

Because the Illuminate\Database\Migrations\Migrator::getMigrationFiles() now contains this code: return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php'); (see the source code.)


But in my usecase, I actually wanted to run a set of migrations at the same time, not just one, or all.

So I went the Laravel way and registered a different implementation of the Migrator, which decides which files to use:

/**
 * A migrator that can run multiple specifically chosen migrations.
 */
class MigrationsSetEnabledMigrator extends Migrator
{
    /**
     * @param Migrator $migrator
     */
    public function __construct(Migrator $migrator)
    {
        parent::__construct($migrator->repository, $migrator->resolver, $migrator->files);

        // Compatibility with versions >= 5.8
        if (isset($migrator->events)) {
            $this->events = $migrator->events;
        }
    }

    /**
     * Get all of the migration files in a given path.
     *
     * @param  string|array $paths
     * @return array
     */
    public function getMigrationFiles($paths)
    {
        return Collection::make($paths)->flatMap(function ($path) {
            return Str::endsWith($path, ']') ? $this->parseArrayOfPaths($path) :
                (Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path . '/*_*.php'));
        })->filter()->sortBy(function ($file) {
            return $this->getMigrationName($file);
        })->values()->keyBy(function ($file) {
            return $this->getMigrationName($file);
        })->all();
    }

    public function parseArrayOfPaths($path)
    {
        $prefix = explode('[', $path)[0];
        $filePaths = explode('[', $path)[1];
        $filePaths = rtrim($filePaths, ']');

        return Collection::make(explode(',', $filePaths))->map(function ($filePath) use ($prefix) {
            return $prefix . $filePath;
        })->all();
    }
}

We have to register it into the container as 'migrator' (to be accessible as $app['migrator']), because that is how Migrate command accesses it when itself is being registered into the IoC. To do so, we put this code into a service provider (in my case, it is a DatabaseServiceProvider):

    public function register()
    {
        $this->app->extend('migrator', function ($migrator, $app) {
            return new MultipleSpecificMigrationsEnabledMigrator($migrator);
        });

        // We reset the command.migrate bind, which uses the migrator - to 
        // force refresh of the migrator instance.
        $this->app->instance('command.migrate', null);
    }

Then you can run this:

php artisan migrate --path=[database/migrations/my_migration.php,database/migrations/another_migration.php]

Notice the multiple migration files, separated by a comma.

It is tested and working in Laravel 5.4 and should be Laravel 5.8 compatible.

Why?

For anyone interested: the usecase is updating the version of database along with it's data.

Imagine, for example, that you wanted to merge the street and house number of all users into new column, let's call it street_and_house. And imagine you wanted to do that on multiple installations in a safe and tested way - you would probably create a script for that (in my case, I create data versioning commands - artisan commands).

To do such an operation, you first have to load the users into memory; then run the migrations to remove the old columns and add the new one; and then for each user assign the street_and_house=$street . " " . $house_no and save the users. (I am simplifying here, but you can surely imagine other scenarios)

And I do not want to rely on the fact that I can run all the migrations at any given time. Imagine that you wanted to update it from let's say 1.0.0 to 1.2.0 and there were multiple batches of such updates – performing any more migrations could break your data, because those migrations must be handled by their own dedicated update command. Therefore, I want to only run the selected known migrations which this update knows how to work with, then perform operations on the data, and then possibly run the next update data command. (I want to be as defensive as possible).

To achieve this, I need the aforementioned mechanism and define a fixed set of migrations to be run for such a command to work.

Note: I would have preferred to use a simple decorator utilizing the magic __call method and avoid inheritance (a similar mechanism that Laravel uses in the \Illuminate\Database\Eloquent\Builder to wrap the \Illuminate\Database\Query\Builder), but the MigrateCommand, sadly, requires an instance of Migrator in it's constructor.


Final note: I wanted to post this answer to the question How can I run specific migration in laravel , as it is Laravel 5 - specific. But I can not - since that question is marked as a duplicate of this one (although this one is tagged as Laravel 4).

Belorussia answered 16/6, 2019 at 18:33 Comment(0)
H
0

It's also possble to rollback a limited number of migrations by providing the step option to the rollback command. For example, the following command will rollback the last five migrations:

php artisan migrate:rollback --step=5

Hardware answered 6/9, 2023 at 14:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.