Modifiers chain onto a column: nullable(), default(), comment(), collation(), useCurrent(), storedAs() and virtualAs() for generated columns (Generated Columns), and on MySQL 524 after(), first() and invisible(). change() redefines an existing column. The second batch adds an ISBN after sku and widens title; its down() calls dropColumn('isbn') and changes title back to 200. --pretend prints the SQL without running it:
Schema::table('products', function (Blueprint $table) {
$table->char('isbn', 13)->nullable()->unique()->after('sku')
->comment('ISBN-13, books only');
$table->string('title', 255)->change();
});$ php artisan migrate --pretend ... 2026_09_23_081323_add_isbn_to_products_table ............................... ⇂ alter table `products` add `isbn` char(13) null comment 'ISBN-13, books only' after `sku` ⇂ alter table `products` modify `title` varchar(255) not null ⇂ alter table `products` add unique `products_isbn_unique`(`isbn`)
change() is a full redefinition, like MySQL's MODIFY (ALTER TABLE and Online DDL): any modifier you leave out is dropped. A test migration with $table->integer('stock')->change() pretended ` modify stock int not null , losing unsigned and default 0; the safe form, unsignedInteger('stock')->default(0)->change(), kept both. change() leaves indexes alone, and dropColumn() removed the ISBN's unique index with the column. On big tables, instant() and lock('none') append algorithm=instant and lock=none` (ALTER TABLE and Online DDL), so MySQL errors rather than rebuild or block.