Laravel Tutorial · Database and Eloquent · Lesson 13 of 27
Migrations
Create and change database tables in version-controlled PHP files: columns, indexes, foreign keys, and rolling changes back.
Why migrations?
A migration describes a database change in PHP, so every developer and every server gets the same schema by running php artisan migrate. Each migration has up() (apply) and down() (undo).
php artisan make:migration create_posts_table
php artisan migrate # run new migrations
php artisan migrate:rollback # undo the last batch
php artisan migrate:fresh --seed # drop everything, re-run, seed (development only!)
Column types: id(), string(), text(), integer(), decimal('price', 8, 2), boolean(), date(), timestamp(), json(), foreignId('user_id')->constrained(), timestamps(), softDeletes(). Modifiers: nullable(), default(), unique(), index().
To change an existing table, write a new migration with Schema::table(...); never edit migrations that already ran in production.
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
// What would be in database/migrations/..._create_authors_and_books.php up():
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->foreignId('author_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->decimal('price', 8, 2)->default(0);
$table->boolean('published')->default(false)->index();
$table->timestamps();
});
// A later migration adds a column instead of editing the old one:
Schema::table('books', function (Blueprint $table) {
$table->string('isbn', 20)->nullable()->after('title'); // after() orders columns on MySQL; PostgreSQL appends
});
echo 'books columns: ', implode(', ', Schema::getColumnListing('books')), "\n";
echo 'has isbn: ', Schema::hasColumn('books', 'isbn') ? 'yes' : 'no', "\n";
DB::table('authors')->insert(['name' => 'Ana', 'email' => '[email protected]']);
try {
DB::table('books')->insert(['author_id' => 99, 'title' => 'Orphan']); // foreign key protects integrity
} catch (Illuminate\Database\QueryException $e) {
echo 'rejected: foreign key violation', "\n";
}
// down() would reverse it:
Schema::dropIfExists('books');
echo 'books exists after down(): ', Schema::hasTable('books') ? 'yes' : 'no', "\n";
Output
books columns: id, author_id, title, price, published, created_at, updated_at, isbn has isbn: yes rejected: foreign key violation books exists after down(): no
Run this on your computer — see “Get Started” for setup.
Test yourself
A migration already ran in production and you need a new column. What should you do?
Edit the old migrationCreate a new migration that alters the tableChange the column in a GUIRun migrate:fresh in production
Show answer
Answer: Create a new migration that alters the table