In Laravel, what do php artisan migrate --pretend and php artisan schema:dump --prune each do, and what are their limits?
answer
- pretend: queries logged, not executed
- reads inside return nothing
- database/schema/{connection}-schema.sql
- loaded only when nothing has migrated
- --prune deletes database/migrations
basics
~10 smigrate --pretend prints the SQL pending migrations would run without executing it; queries a migration reads return empty. schema:dump writes the schema, with migrations rows, to database/schema/<connection>-schema.sql, and --prune deletes database/migrations.
solid answer
~40 s`migrate --pretend` runs each pending migration against a connection in **pretend mode**: statements are collected into a query log and printed, not sent. Any `select` inside a migration therefore returns nothing, so data-dependent logic prints misleading SQL; `DB::withoutPretending()` runs a callback for real when a read is genuinely needed. `schema:dump` uses the database's command-line client to write `database/schema/<connection>-schema.sql`, including the `migrations` table rows so Laravel knows which files it covers. On a database where **no** migration has run yet, `migrate` loads that file first and then runs only newer migrations. `--prune` deletes the `database/migrations` directory. Squashing works on MariaDB, MySQL, PostgreSQL and SQLite; dump each connection your tests use, since the file is chosen by connection name.
code
bash · 6 linesphp artisan migrate --pretend
php artisan migrate:rollback --pretend
php artisan schema:dump
php artisan schema:dump --database=testing --prune
# writes database/schema/mysql-schema.sql and database/schema/testing-schema.sqlgo deeper
Recall that --pretend shows migration SQL without running it and that schema:dump squashes migrations into one SQL file.
Explain pretend mode's empty reads, where the dump file lives, and that it is loaded only on a database with no migration history.
Use --pretend in deploy reviews knowing its blind spots, and manage per-connection dumps for tests and CI.
Decide when squashing is worth losing per-migration history, and how the team reviews generated SQL before release.
## `migrate --pretend` `php artisan migrate --pretend` answers "what SQL will this deploy run?" without touching the schema: 1. Laravel finds the pending migrations, exactly as `migrate` would. 2. For each one it calls `up()` inside the connection's **pretend mode**, in which every statement is recorded in a query log instead of being executed. 3. It prints each migration's name followed by the list of statements. The same flag exists on `migrate:rollback` and `migrate:reset`, where it prints what the `down()` methods would run. ### Limits of pretending - **Reads return nothing.** A `select` in pretend mode is not executed, so it yields an empty result. A migration that decides what to do from existing data, for example "add the index only if no duplicates exist", prints SQL for a situation that is not real. - **`DB::withoutPretending(fn () => ...)`** runs its callback for real even during a pretend run, for the rare read a migration genuinely needs. - **Nothing is validated.** Syntax the database would reject, locks it would take, or rows that violate a new constraint only show up when the migration really runs. - **No schema file is loaded.** On an empty database, pretend mode skips loading a schema dump. ## `schema:dump` A long-lived app accumulates hundreds of migrations, and building a test database by replaying them all is slow. `php artisan schema:dump` **squashes** them: - It asks the database's own command-line client to dump the current schema into `database/schema/<connection>-schema.sql`, for example `mysql-schema.sql`. - It includes the **rows of the `migrations` table**, so the dump carries the list of migrations it already contains. - With **`--prune`**, it then deletes the `database/migrations` directory, since everything in it is now inside the dump. ### How the dump is used When `migrate` runs against a database on which **no migrations have run yet**, it looks for the schema file named after the connection, executes it, and then runs only the migrations not recorded in the dumped `migrations` rows. A database that already has migration history ignores the file. | Situation | What `migrate` does | |---|---| | Empty database, dump present | load dump, then newer migrations | | Empty database, no dump | run every migration file | | Existing database | run pending migrations only; dump ignored | | `migrate --pretend` on empty database | skip the dump, print pending SQL | ### Limits of squashing 1. **Supported drivers:** MariaDB, MySQL, PostgreSQL and SQLite. The command shells out to their command-line clients, which must be installed where it runs. 2. **Per connection:** the file name comes from the connection name. If tests use a `testing` connection, dump that one too, for example `php artisan schema:dump --database=testing`. 3. **Commit the file:** new developers and CI build their databases from it. 4. **Pruning is one-way:** after `--prune`, the individual `down()` methods for squashed migrations are gone, so those changes can no longer be rolled back one by one. ## When interviewers bring these up `--pretend` usually appears in a question about reviewing a risky deploy; `schema:dump` in one about slow test suites or a migrations folder nobody can read. Knowing that pretend mode fakes reads, and that the dump only applies to a database with no migration history, is what separates having used them from having read the command list.
- After schema:dump --prune, a teammate's existing local database still has migration history. What happens when they run migrate?Nothing from the dump is applied, because the file is only loaded when no migrations have run. Their database already matches the dumped schema, and `migrate` only runs any newer migration files. The dump matters for fresh databases, such as a new developer's machine or CI.
- A migration's --pretend output shows no UPDATE statements, but in production it updated thousands of rows. Why?The migration probably read rows first, for example with `DB::table('orders')->whereNull('currency')->get()`, and looped over them. In pretend mode that `select` is not executed and returns nothing, so the loop never ran and no `UPDATE` was logged. Pretend output only reflects statements whose issuing does not depend on data.
saying these in an interview costs you the question
- Thinks --pretend runs the migrations inside a transaction and rolls back
- Expects reads inside a pretended migration to return real rows
- Believes the schema dump is loaded on every migrate
- Assumes schema:dump works without the database's CLI client
- Forgets to dump the testing connection's schema