Database Migrations: Version Control for Your Schema
Migrations let you define your database schema in PHP code, making it versionable, shareable, and deployable.
Creating a Migration
php artisan make:migration create_posts_table
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('category_id')->constrained();
$table->string('title');
$table->string('slug')->unique();
$table->text('excerpt')->nullable();
$table->longText('body');
$table->string('cover_image')->nullable();
$table->boolean('is_published')->default(false)->index();
$table->boolean('is_featured')->default(false);
$table->timestamp('published_at')->nullable();
$table->unsignedInteger('views_count')->default(0);
$table->timestamps();
// Composite index for common queries
$table->index(['is_published', 'published_at']);
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Column Modifiers
$table->string('email')->unique();
$table->text('bio')->nullable();
$table->integer('sort_order')->default(0);
$table->decimal('price', 10, 2)->unsigned();
$table->enum('status', ['draft', 'published', 'archived']);
$table->json('metadata')->nullable();
$table->softDeletes(); // Adds deleted_at column
Modifying Existing Tables
php artisan make:migration add_subtitle_to_posts_table
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->string('subtitle')->nullable()->after('title');
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('subtitle');
});
}
Migration Commands
php artisan migrate # Run pending migrations
php artisan migrate:rollback # Undo last batch
php artisan migrate:status # Check migration status
php artisan migrate:fresh --seed # Drop all, re-migrate, seed
Always write a down() method so migrations are reversible. In production, use php artisan migrate --force in your deployment script.