Reader Stacks

Laravel Migrations: Creating and Running Them

A migration is a version-controlled, reversible description of one schema change — the file, the up()/down() methods, and the commands that actually apply or undo it.

A Laravel migration is a PHP class describing one schema change, checked into version control alongside the code that depends on it — so every environment (a teammate's machine, staging, production) can reach an identical database structure by running the same ordered set of files, instead of relying on someone manually running SQL by hand.

1. Creating a migration

php artisan make:migration create_products_table

Laravel infers intent from the migration's name — create_products_table pre-fills a Schema::create stub for a new table; add_price_to_products_table pre-fills an Schema::table stub for altering an existing one. The generated file lands in database/migrations/ with a timestamp prefix, which is what determines run order.

public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->decimal('price', 10, 2);
        $table->timestamps();
    });
}

public function down(): void
{
    Schema::dropIfExists('products');
}

2. up() and down()

up() applies the change; down() must undo exactly what up() did, in reverse. This isn't a formality — down() is what actually runs when a migration is rolled back, and a down() that doesn't correctly reverse the corresponding up() leaves the schema in a state that no longer matches what any migration file describes.

3. Running migrations

php artisan migrate

This runs every migration that hasn't already been applied, in timestamp order, and records each one in the migrations table — which is how Laravel knows which migrations are "new" the next time the command runs, rather than re-applying everything from scratch.

4. Rolling back

php artisan migrate:rollback           # undo the last batch
php artisan migrate:rollback --step=3  # undo the last 3 migrations
php artisan migrate:reset              # undo everything

A "batch" is every migration that ran together in a single migrate call — rollback without --step undoes that whole batch at once, in reverse order, not just the single most recent file.

5. Fresh and refresh, for local development

php artisan migrate:fresh   # drop every table, then re-run all migrations
php artisan migrate:refresh # roll back everything, then re-run all migrations

migrate:fresh is faster because it drops tables directly rather than running every migration's down() method — the practical difference is that fresh skips validating that each down() actually works. Neither command belongs anywhere near a production database; both destroy all existing data.

6. Checking migration status

php artisan migrate:status

Lists every migration file alongside whether it's been run — the fastest way to check, before deploying, whether a teammate's new migration has already been applied on a given environment or is still pending.

Topics: Database Migrations