Migrations
Managing database schema with Migrations
Migrations allow you to manage database schema with version control. This system allows you to apply database schema changes incrementally and reversibly.
Benefits of Using Migrations:
- <strong>Version Control</strong>: All schema changes are stored in migration files
- <strong>Team Collaboration</strong>: Team members can easily sync schema
- <strong>Environment Consistency</strong>: Same schema across all environments (development, staging, production)
- <strong>Rollback Support</strong>: Ability to rollback changes if needed
- <strong>History Tracking</strong>: Complete history of schema changes
- <strong>Automation</strong>: Automatic migration execution in deployment
Migration Structure:
Each migration file contains two methods:
- <code>up()</code>: Changes that should be applied (create table, add column, etc.)
- <code>down()</code>: Changes that should be rolled back (drop table, remove column, etc.)
Naming Conventions:
- Migration files are prefixed with timestamp
- Migration name should be descriptive
- Use snake_case for migration name
Migration Types:
- <strong>Create Table</strong>: Create new table
- <strong>Alter Table</strong>: Modify existing table
- <strong>Drop Table</strong>: Drop table
- <strong>Add Column</strong>: Add column
- <strong>Modify Column</strong>: Modify column
- <strong>Drop Column</strong>: Drop column
- <strong>Create Index</strong>: Create index
- <strong>Drop Index</strong>: Drop index
Best Practices:
- Each migration should perform one specific change
- Use transactions for migrations
- Commit migration files
- Use descriptive names
- Always implement down() method
Examples
Creating Migration
php artisan make:migration create_users_table
php artisan make:migration add_email_to_users_table --table=users
php artisan make:migration drop_users_table --table=users
Artisan commands to create different types of migrations.
Migration File - Create Table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
};
A complete migration to create users table with all columns.
Migration - Add Column
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('phone')->nullable()->after('email');
$table->boolean('is_active')->default(true);
$table->index('email');
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['phone', 'is_active']);
$table->dropIndex(['email']);
});
}
};
Adding new columns to existing table.
Migration - Foreign Keys
<?php
return new class extends Migration
{
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')
->constrained()
->onDelete('cascade');
$table->foreignId('category_id')
->nullable()
->constrained()
->onDelete('set null');
});
}
public function down()
{
Schema::table('posts', function (Blueprint $table) {
$table->dropForeign(['user_id']);
$table->dropForeign(['category_id']);
$table->dropColumn(['user_id', 'category_id']);
});
}
};
Adding foreign keys with cascade and set null options.
Migration - Indexes
<?php
return new class extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->index('email');
$table->unique('username');
$table->index(['status', 'created_at']);
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropIndex(['email']);
$table->dropUnique(['username']);
$table->dropIndex(['status', 'created_at']);
});
}
};
Creating indexes to improve query performance.
Running Migrations
php artisan migrate
php artisan migrate:status
php artisan migrate:rollback
php artisan migrate:rollback --step=3
php artisan migrate:refresh
php artisan migrate:fresh
php artisan migrate:reset
Artisan commands to run and manage migrations.
Migration with Raw SQL
<?php
return new class extends Migration
{
public function up()
{
DB::statement('ALTER TABLE users ADD FULLTEXT INDEX fulltext_name (name)');
}
public function down()
{
DB::statement('ALTER TABLE users DROP INDEX fulltext_name');
}
};
Using raw SQL for complex operations not possible with Blueprint.
Use Cases
- Managing schema changes in version control
- Synchronizing database schema between environments
- Rolling back schema changes if problems occur
- Team collaboration for database changes
- Automated deployment with schema updates
- Tracking history of database changes
Common Mistakes
- Forgetting to implement down() method
- Creating migration with too many changes making rollback difficult
- Not using transactions for migrations
- Forgetting foreign keys in migrations
- Not using indexes for performance
- Modifying migration files that have already been run
Best Practices
- Always implement down() method
- Each migration should perform one specific change
- Use descriptive names for migrations
- Use transactions for migrations
- Define foreign keys in migrations
- Add indexes for frequently queried columns
- Commit migration files and don't modify them
Edge Cases
- Migrations with large datasets that may be slow
- Migrations with data transformation
- Migrations with multiple database connections
- Migrations with custom database drivers
- Rollback migrations with data loss
- Migrations with conflicting changes
Performance Notes
- Use indexes for frequently queried columns
- Use batch operations for large data migrations
- Use transactions for atomic operations
- Use chunking for processing large datasets
- Use raw queries for complex operations
- Monitor migration execution time
Security Notes
- Ensure migration files are in version control
- Use raw SQL with caution
- Ensure no sensitive data in migrations
- Use environment variables for configuration
- Ensure migrations are properly tested in production
Interview Points
- What are migrations and why are they used?
- What is the difference between migrate and migrate:fresh?
- How can you rollback a migration?
- Why should we implement down() method?
- How can you add foreign key in migration?
- What is the difference between migrate:refresh and migrate:reset?
Version Notes
- Laravel 11.x: Improved performance in migration execution
- Laravel 11.x: Better support for anonymous migrations
- Laravel 10.x: Improved foreign key constraints
- Laravel 9.x: Improved Blueprint API