Database migrations bring version control to your schema. Instead of sharing SQL files, Laravel migrations track changes in code, making collaboration and deployment seamless. At ZIRA Software, migrations are essential to our development workflow.
Creating Migrations
# Create a migration
php artisan make:migration create_posts_table
# Create with table stub
php artisan make:migration create_posts_table --create=posts
# Create for modifying existing table
php artisan make:migration add_published_to_posts --table=posts
Migration Structure
// database/migrations/2015_11_20_000000_create_posts_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('title');
$table->string('slug')->unique();
$table->text('content');
$table->boolean('published')->default(false);
$table->timestamp('published_at')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->index(['published', 'published_at']);
});
}
public function down()
{
Schema::dropIfExists('posts');
}
}
Column Types
Schema::create('products', function (Blueprint $table) {
// Primary keys
$table->increments('id');
$table->bigIncrements('id');
// Strings
$table->char('code', 10);
$table->string('name', 255);
$table->text('description');
$table->longText('content');
// Numbers
$table->integer('quantity');
$table->bigInteger('views');
$table->decimal('price', 8, 2);
$table->float('rating', 3, 2);
// Boolean and dates
$table->boolean('active');
$table->date('release_date');
$table->dateTime('scheduled_at');
$table->timestamp('processed_at');
$table->time('opens_at');
// Special types
$table->binary('file_data');
$table->enum('status', ['draft', 'published', 'archived']);
$table->json('metadata');
$table->uuid('uuid');
$table->ipAddress('visitor_ip');
$table->macAddress('device_mac');
// Timestamps
$table->timestamps(); // created_at, updated_at
$table->softDeletes(); // deleted_at
});
Modifying Tables
// Add columns
Schema::table('posts', function (Blueprint $table) {
$table->string('featured_image')->nullable()->after('content');
$table->integer('view_count')->default(0)->after('featured_image');
});
// Rename column
Schema::table('posts', function (Blueprint $table) {
$table->renameColumn('content', 'body');
});
// Change column type
Schema::table('posts', function (Blueprint $table) {
$table->text('title')->change(); // string to text
});
// Drop column
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('featured_image');
$table->dropColumn(['view_count', 'rating']);
});
Indexes and Foreign Keys
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->integer('post_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->text('body');
$table->timestamps();
// Foreign keys
$table->foreign('post_id')
->references('id')
->on('posts')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
// Indexes
$table->index('post_id');
$table->index('user_id');
$table->index('created_at');
// Composite index
$table->index(['post_id', 'created_at']);
});
// Drop foreign key
Schema::table('comments', function (Blueprint $table) {
$table->dropForeign(['post_id']);
$table->dropIndex(['post_id']);
});
Running Migrations
# Run all pending migrations
php artisan migrate
# Rollback last batch
php artisan migrate:rollback
# Rollback all migrations
php artisan migrate:reset
# Rollback and re-run all
php artisan migrate:refresh
# Show migration status
php artisan migrate:status
# Run in production (with confirmation)
php artisan migrate --force
Database Seeders
// database/seeds/PostsTableSeeder.php
class PostsTableSeeder extends Seeder
{
public function run()
{
// Using factory
factory(App\Post::class, 50)->create();
// Manual insertion
DB::table('posts')->insert([
'title' => 'First Post',
'slug' => 'first-post',
'content' => 'Welcome to our blog!',
'user_id' => 1,
'published' => true,
'created_at' => now(),
'updated_at' => now(),
]);
}
}
// database/seeds/DatabaseSeeder.php
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call([
UsersTableSeeder::class,
PostsTableSeeder::class,
CommentsTableSeeder::class,
]);
}
}
# Run seeders
php artisan db:seed
# Run specific seeder
php artisan db:seed --class=PostsTableSeeder
# Migrate and seed
php artisan migrate --seed
Conclusion
Migrations transform database management from ad-hoc SQL scripts to version-controlled, collaborative code. Combined with seeders and factories, Laravel provides complete database lifecycle management.
Need database architecture help? Contact ZIRA Software for consultation.