In Laravel, what does php artisan make:migration create_listings_table generate, and how do its up() and down() methods relate to migrate and migrate:rollback?
answer
- timestamped file in database/migrations
- return new class extends Migration
- Schema::create with id() and timestamps()
- migrations table stores name and batch
- rollback runs down() for the last batch
basics
~20 sIt writes a timestamped file in database/migrations that returns an anonymous class extending Migration, with up() creating the listings table and down() dropping it. migrate runs pending up() methods as one batch; migrate:rollback runs down() for the last batch.
solid answer
~30 s`make:migration create_listings_table` guesses the table from the `create_*_table` pattern and writes `database/migrations/<timestamp>_create_listings_table.php`. The file `return`s an **anonymous class** extending `Illuminate\Database\Migrations\Migration`, so two migrations can never collide on a class name. Its `up()` calls `Schema::create('listings', ...)` with `$table->id()` and `$table->timestamps()`; its `down()` calls `Schema::dropIfExists('listings')`. A name like `add_price_to_listings_table` instead produces `Schema::table()` calls for an existing table. `php artisan migrate` runs every migration not yet recorded in the `migrations` table, in filename order, and records them with a new **batch** number. `migrate:rollback` runs `down()` for the migrations in the latest batch and deletes their records, so `down()` must exactly undo `up()`.
code
bash · 5 linesphp artisan make:migration create_listings_table
php artisan make:migration add_price_to_listings_table
php artisan migrate
php artisan migrate:status
php artisan migrate:rollbackgo deeper
Recall the anonymous class returned by the file, Schema::create versus Schema::table, and that migrate runs up() while rollback runs down().
Explain the migrations table and batch numbers, how make:migration picks a stub from the name, and why down() must mirror up().
Enforce that shipped migrations are immutable and reversible, and keep application models out of them so old migrations keep working.
Set the team's rules for migration granularity, review and reversibility across many contributors and environments.
## What the generator writes A **migration** is a PHP file that describes one change to the database schema. Laravel keeps them in `database/migrations`, and each filename starts with a timestamp so that files sort in the order they were created: ```bash php artisan make:migration create_listings_table # database/migrations/2026_09_29_101500_create_listings_table.php ``` The command inspects the name. A `create_*_table` name (or `--create=listings`) produces a **create** stub; a name ending in `_to_listings_table`, `_from_listings_table` or `_in_listings_table` (or `--table=listings`) produces an **update** stub that uses `Schema::table()`. The create stub looks like this: ```php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::create('listings', function (Blueprint $table) { $table->id(); $table->timestamps(); }); } public function down(): void { Schema::dropIfExists('listings'); } }; ``` ## Why an anonymous class The file **returns** an instance of a class with no name. Older Laravel migrations declared named classes such as `CreateListingsTable`, which meant two migrations with the same name in one project collided. Because the migrator simply `require`s the file and uses the object it returns, anonymous classes remove that problem. ## `Schema::create` versus `Schema::table` - **`Schema::create('listings', fn (Blueprint $table) => ...)`** issues `CREATE TABLE`. The closure receives a `Blueprint`, on which each method call declares a column or index: `$table->string('title')`, `$table->decimal('price', 10, 2)`. - **`Schema::table('listings', ...)`** alters an existing table: add columns, add or drop indexes, or modify columns with `change()`. - **`$table->id()`** adds an auto-incrementing unsigned big-integer primary key named `id`; **`$table->timestamps()`** adds nullable `created_at` and `updated_at`. ## How `migrate` and `rollback` use the two methods Laravel records every migration it has run in a table named `migrations`, with the file name and a **batch** number: 1. `php artisan migrate` compares the files on disk with the rows in `migrations`, runs `up()` on each pending file in filename order, and records them all with the next batch number. 2. `php artisan migrate:rollback` finds the **latest batch**, runs `down()` on each of its migrations in reverse order, and deletes their rows. 3. `php artisan migrate:status` lists each migration with whether it has run and in which batch. Because rollback trusts `down()`, it must be the exact inverse of `up()`: a migration that adds two columns and an index should drop all three. An empty `down()` makes a rollback report success while leaving the schema unchanged. ## Habits that keep migrations healthy - **Never edit a migration that has already run** on a shared or production database. Laravel sees it as done and will not run it again; write a new migration instead. - **One concern per migration** makes rollbacks predictable. - **Keep models out of migrations** where possible: a model's code changes over time, while a migration must keep working against the schema as it was when it ran. ## Summary | Piece | Role | |---|---| | `make:migration` | writes a timestamped file from a create or update stub | | anonymous class | avoids class-name collisions between migrations | | `up()` | applies the change, run by `migrate` | | `down()` | reverses it, run by `migrate:rollback` | | `migrations` table | records which files ran, and in which batch |
- You fixed a typo in a migration that already ran in production. Why does migrate report nothing to do?The migrator only compares file names with the rows in the `migrations` table. The edited file's name is already recorded, so Laravel treats it as done and never reads its new contents. Revert the edit and add a new migration that makes the correction, so every environment converges on the same schema.
- What does make:migration generate when the name matches neither a create nor a change pattern?A blank stub whose `up()` and `down()` are empty, because Laravel cannot guess a table. Pass `--create=listings` or `--table=listings` to choose the create or update stub explicitly, or fill the methods in yourself.
saying these in an interview costs you the question
- Thinks migrate re-runs a migration after its file is edited
- Leaves down() empty and expects rollback to undo the change
- Believes migrate:rollback reverts every migration ever run
- Says migrations must declare a uniquely named class
- Uses Schema::create to add a column to an existing table