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.

Create a free account to save this page, take notes and track your progress. Sign in

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.

Creating and altering tables
<?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?

  1. Edit the old migration
  2. Create a new migration that alters the table
  3. Change the column in a GUI
  4. Run migrate:fresh in production
Show answer

Answer: Create a new migration that alters the table

Was this page helpful?