Lavavel Migrations
A migration is a version-controlled instruction for building your database. Think of it as a recipe — one your whole team agrees on, stores in Git, and runs in order.
When you run php artisan migrate , Laravel reads every migration file you haven’t run yet (it tracks these in a migrations table) and executes them top to bottom, in chronological order, Every developer on your tram, every server and every deployment ends up with exact same schema state.
Every migration file has two methods:
up()– runs when you migrate. Creates tables, columns and builddown()– runs when you rollback. Undoes whatup()did.
This reversibility is the whole point. Made a mistake? php artisan migrate:rollback. Roll back, fix it, migrate again.
How to create a Migration?
When you run php artisan make:migration Laravel give your the bare minimum.This is intentionally empty. It’s your blank canvas.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
//
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};
Now lets add a bit more detail to the migration. In this example we just want to add more details to make sure we can see a users tasks, with a title, if its completed and the relevant timestamps.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};
foreignId('user_id)->constrained() – this creates a foreign key constraint in the database itself. It means the DB will refuse to insert a task with a user_id that doesn’t exist in the users table. The is referential integrity – the database enforces your data rules, not just your application.
casecadeOnDelete() – when a user is deleted, all their tasks are automatically deleted too. Or the alternative is ->nullOnDelete() sets the user_id to null which leaves orphaned records.
default(false) – sets the column default to the provided valued. Not just the PHP default. Important because if you ever insert a row bypassing Laravel (raw SQL, a seeder, a migration script), it still gets the right default.
Summary
Migrations are one of those Laravel features that quietly make your life easier — your schema is versioned, reversible, and shared across every environment. Once it clicks, you’ll wonder how you ever managed a database without them. Happy Coding!.