Laravel Logo

Now that we’ve learned how to create our migrations it’s time to discuss how to work with them using the migrate family of commands.

Why It Exists

As we discussed in our previous article, database migrations allow you to define changes to your database so you can easily apply the changes everywhere you maintain a copy of the database for the application. The migrate family of commands gives us control over applying those migrations to the database.

When Should You Use It

Any time you’re editing the structure of a table.

Overview

As a quick review here’s what the migrate family of commands looks like in the help display.

 
 migrate
  migrate:fresh        Drop all tables and re-run all migrations
  migrate:install      Create the migration repository
  migrate:refresh      Reset and re-run all migrations
  migrate:reset        Rollback all database migrations
  migrate:rollback     Rollback the last database migration
  migrate:status       Show the status of each migration

migrate:install

The migrate:install command creates the “migrations” table inside the database. This table is used to keep track of the migrations that have been run against the database. I’m guessing this command exists as a form of completionism because some of the commands below automatically create this table when it’s missing.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:install
Migration table created successfully.

The migrations table itself is super simple:

mysql> show columns from migrations;
+-----------+------------------+------+-----+---------+----------------+
| Field     | Type             | Null | Key | Default | Extra          |
+-----------+------------------+------+-----+---------+----------------+
| id        | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| migration | varchar(255)     | NO   |     | NULL    |                |
| batch     | int(11)          | NO   |     | NULL    |                |
+-----------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

migrate:status

The migrate:status command displays the status all the migrations you have defined.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 2     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 3     |
| No   | 2019_10_11_011555_create_tasks_table           |       |
+------+------------------------------------------------+-------+

The main items to highlight here are:

  1. The “Ran?” column which display if the migration has been run against the current database
  2. The “Migration” column which displays the name of the migration
  3. The “Batch” column which displays in what order the migrations were run.

In the example above I ran the first three migrations separately but if I had run them at the same time I would have ended up with with the results below.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 1     |
| No   | 2019_10_11_011555_create_tasks_table           |       |
+------+------------------------------------------------+-------+

migrate

The migrate command runs any migrations that have not been run against the database. It uses the up() function inside the migration to determine what to do.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate
Migrating: 2019_10_11_011555_create_tasks_table
Migrated:  2019_10_11_011555_create_tasks_table (0.08 seconds)

Now if we look at the current status we’ll see that “2019_10_11_011555_create_tasks_table” was applied in it’s own batch.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 2     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 3     |
| Yes  | 2019_10_11_011555_create_tasks_table           | 4     |
+------+------------------------------------------------+-------+

migrate:rollback

The migrate:rollback command takes the list of migrations in the last batch number and runs their down() function.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:rollback
Rolling back: 2019_10_11_011555_create_tasks_table
Rolled back:  2019_10_11_011555_create_tasks_table (0.02 seconds)

Now we can look at the status and see that “2019_10_11_011555_create_tasks_table” is no longer listed as being run.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 2     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 3     |
| No   | 2019_10_11_011555_create_tasks_table           |       |
+------+------------------------------------------------+-------+

migrate:fresh

The migrate:fresh command deletes all existing tables and then runs all the migrations.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:fresh
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.09 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.04 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.01 seconds)
Migrating: 2019_10_11_011555_create_tasks_table
Migrated:  2019_10_11_011555_create_tasks_table (0.03 seconds)
ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 1     |
| Yes  | 2019_10_11_011555_create_tasks_table           | 1     |
+------+------------------------------------------------+-------+

Be careful with this command. “Dropped all tables successfully” includes any tables that aren’t being managed by the migrations. We’re in the process of migrating to Laravel and running php artisan migrate:fresh deleted all the tables that we hadn’t created using Laravel migrations. Thank goodness it was on a development VM. :-)

migrate:refresh

The migrate:refresh command rolls back all the migrations and then runs them again.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:refresh
Rolling back: 2019_10_11_011555_create_tasks_table
Rolled back:  2019_10_11_011555_create_tasks_table (0.01 seconds)
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back:  2019_08_19_000000_create_failed_jobs_table (0.01 seconds)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table (0.02 seconds)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table (0.01 seconds)
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.03 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.05 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.01 seconds)
Migrating: 2019_10_11_011555_create_tasks_table
Migrated:  2019_10_11_011555_create_tasks_table (0.05 seconds)

Now if we look at our migration status we’ll see everything was applied in one big batch.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 1     |
| Yes  | 2019_10_11_011555_create_tasks_table           | 1     |
+------+------------------------------------------------+-------+

migrate:reset

The migrate:reset command rolls back all the migrations and then stops.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:reset
Rolling back: 2019_10_11_011555_create_tasks_table
Rolled back:  2019_10_11_011555_create_tasks_table (0.02 seconds)
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back:  2019_08_19_000000_create_failed_jobs_table (0.01 seconds)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table (0 seconds)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table (0 seconds)

If we look at migrate:status now, none of the migrations have been run.

ubuntu@ubuntu-xenial:/var/www$ php artisan migrate:status
+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| No   | 2014_10_12_000000_create_users_table           |       |
| No   | 2014_10_12_100000_create_password_resets_table |       |
| No   | 2019_08_19_000000_create_failed_jobs_table     |       |
| No   | 2019_10_11_011555_create_tasks_table           |       |
+------+------------------------------------------------+-------+

When Do I Use These Commands?

  • status, migrate and rollback are the bread and butter of this family of functions. You’ll be using them all the time.
  • fresh and refresh are used if you need to reset your database to a clean state.
  • reset is a mystery to me. I can’t think of any good reason you would want to rollback every migration and then stop. Sound off in the comments if you have an explanation.

Hopefully this has been as helpful to you as it has to me and check back soon for more artisan commands.