Database Configuration & Migrations
Database Configuration & Migrations
Laravel makes database interactions simple and elegant. In this lesson, you'll learn how to configure database connections, create and manage migrations, and use Laravel's powerful Schema Builder to define your database structure.
Database Configuration
Laravel supports multiple database systems out of the box: MySQL, PostgreSQL, SQLite, and SQL Server. Database configuration is stored in config/database.php and uses environment variables from your .env file.
.env file, never commit them to version control. The .env file should be listed in your .gitignore.
Setting Up Database Connection
Open your .env file and configure your database connection:
# MySQL Configuration
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=root
DB_PASSWORD=your_password
# SQLite Configuration (Alternative)
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite
After configuring your database, test the connection by running:
php artisan migrate:status
Introduction to Migrations
Migrations are like version control for your database. They allow you to define and share your application's database schema. Each migration file contains instructions to create, modify, or delete database tables.
Creating Your First Migration
Use the Artisan command to create a new migration:
# Create a migration for a new table
php artisan make:migration create_products_table
# Create a migration to modify an existing table
php artisan make:migration add_price_to_products_table --table=products
# Create a migration with automatic schema generation
php artisan make:migration create_categories_table --create=categories
This creates a new file in database/migrations/ with a timestamp prefix like 2026_02_14_120000_create_products_table.php.
Migration Structure
Every migration file contains two methods: up() and down().
<?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('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 8, 2);
$table->integer('quantity')->default(0);
$table->boolean('is_available')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
Schema Builder - Column Types
Laravel's Schema Builder provides many column types for defining your database structure:
// Primary Keys
$table->id(); // UNSIGNED BIGINT auto-increment
$table->uuid('uuid'); // UUID column
// String Columns
$table->string('name', 100); // VARCHAR with optional length
$table->text('description'); // TEXT column
$table->char('code', 10); // CHAR with fixed length
// Numeric Columns
$table->integer('votes'); // INTEGER
$table->bigInteger('views'); // BIGINT
$table->decimal('price', 8, 2); // DECIMAL with precision
$table->float('rating', 8, 2); // FLOAT
$table->double('latitude', 15, 8); // DOUBLE
// Boolean
$table->boolean('is_active'); // BOOLEAN/TINYINT(1)
// Date and Time
$table->date('birth_date'); // DATE
$table->time('alarm_time'); // TIME
$table->datetime('created_at'); // DATETIME
$table->timestamp('updated_at'); // TIMESTAMP
$table->timestamps(); // created_at & updated_at
$table->softDeletes(); // deleted_at for soft deletes
// JSON and Arrays
$table->json('options'); // JSON column
$table->jsonb('settings'); // JSONB (PostgreSQL)
// Binary
$table->binary('photo'); // BLOB
Column Modifiers
Modifiers allow you to add additional properties to columns:
Schema::create('users', function (Blueprint $table) {
$table->id();
// Nullable columns
$table->string('middle_name')->nullable();
// Default values
$table->string('status')->default('pending');
$table->integer('points')->default(0);
// Unsigned (positive numbers only)
$table->integer('age')->unsigned();
// Unique constraint
$table->string('email')->unique();
$table->string('username')->unique();
// Index for faster queries
$table->string('last_name')->index();
// Comments
$table->string('status')->comment('User account status');
// After specific column (MySQL)
$table->string('phone')->after('email');
// First column position (MySQL)
$table->string('priority')->first();
// Multiple modifiers
$table->string('referral_code', 20)
->nullable()
->unique()
->comment('User referral code');
$table->timestamps();
});
after() and first() are MySQL-specific and won't work with PostgreSQL or SQLite.
Foreign Keys and Relationships
Define relationships between tables using foreign keys:
Schema::create('orders', function (Blueprint $table) {
$table->id();
// Foreign key - long form
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade')
->onUpdate('cascade');
// Foreign key - short form
$table->foreignId('product_id')
->constrained()
->onDelete('cascade');
// Foreign key with custom table name
$table->foreignId('category_id')
->constrained('product_categories')
->onDelete('set null');
$table->integer('quantity');
$table->decimal('total', 10, 2);
$table->timestamps();
});
Running Migrations
Execute your migrations to create the database structure:
# Run all pending migrations
php artisan migrate
# Run migrations with seed data
php artisan migrate --seed
# Rollback the last batch of migrations
php artisan migrate:rollback
# Rollback specific number of batches
php artisan migrate:rollback --step=3
# Rollback all migrations
php artisan migrate:reset
# Rollback all and re-run migrations
php artisan migrate:refresh
# Rollback all, re-run, and seed
php artisan migrate:refresh --seed
# Drop all tables and re-run migrations
php artisan migrate:fresh
# Show migration status
php artisan migrate:status
php artisan migrate carefully. Always backup your database before running migrations that modify existing tables.
Modifying Existing Tables
Create a migration to modify an existing 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(): void
{
Schema::table('products', function (Blueprint $table) {
// Add new columns
$table->string('sku')->unique()->after('name');
$table->integer('discount')->default(0)->after('price');
// Modify existing column
$table->text('description')->nullable()->change();
// Rename column
$table->renameColumn('quantity', 'stock_quantity');
// Drop column
$table->dropColumn('is_available');
// Add index
$table->index('sku');
// Add foreign key
$table->foreignId('category_id')
->nullable()
->constrained()
->onDelete('set null');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropForeign(['category_id']);
$table->dropColumn(['sku', 'discount', 'category_id']);
$table->renameColumn('stock_quantity', 'quantity');
$table->boolean('is_available')->default(true);
});
}
};
composer require doctrine/dbal
Create a migration for a posts table with the following structure:
- id (primary key)
- user_id (foreign key to users table)
- category_id (foreign key to categories table, nullable)
- title (string, max 200 characters)
- slug (string, unique)
- excerpt (text, nullable)
- content (text)
- featured_image (string, nullable)
- views (integer, default 0)
- is_published (boolean, default false)
- published_at (timestamp, nullable)
- timestamps (created_at, updated_at)
- soft deletes (deleted_at)
Use appropriate column types, modifiers, and foreign key constraints.
Create a migration to add indexes to the posts table:
- Single index on
slug - Composite index on
user_idandis_published - Full-text index on
titleandcontent(MySQL only)
Remember to include the down() method to drop these indexes.
Create a migration for a many-to-many relationship between posts and tags:
- Table name:
post_tag - Foreign keys:
post_idandtag_id - Both foreign keys should cascade on delete
- Add a unique composite index on both columns
- Add timestamps
Best Practices
- Atomic Migrations: Each migration should focus on a single change. Don't combine multiple unrelated changes.
- Reversible Migrations: Always implement the
down()method so migrations can be rolled back. - Test Locally: Always test migrations on your local database before running them in production.
- Backup Production: Always backup your production database before running migrations.
- Use Transactions: Laravel wraps migrations in transactions automatically (on supported databases).
- Naming Conventions: Use descriptive migration names:
create_posts_table,add_featured_to_posts.
Summary
In this lesson, you've learned:
- How to configure database connections in Laravel
- Creating and structuring migration files
- Using the Schema Builder with various column types
- Applying column modifiers for constraints and properties
- Defining foreign key relationships
- Running, rolling back, and managing migrations
- Modifying existing tables safely
Migrations are the foundation of your database structure in Laravel. Master them, and you'll have complete control over your application's data layer.