Migraciones
Las migraciones son como un control de versiones para tu base de datos. Permiten definir la estructura de las tablas con código PHP, compartirla con tu equipo y ejecutar cambios de forma segura.
¿Qué son las migraciones?
Las migraciones son archivos PHP que definen cambios en la estructura de la base de datos. Cada migración representa una modificación: crear una tabla, añadir una columna, crear un índice, etc.
Las migraciones resuelven varios problemas:
- Versionado: Los cambios quedan registrados en Git
- Colaboración: Todos en el equipo tienen la misma estructura
- Reproducibilidad: Puedes recrear la base de datos desde cero
- Rollback: Puedes revertir cambios si algo sale mal
Migraciones por defecto
Laravel incluye varias migraciones en
database/migrations/. Al crear un
proyecto nuevo encontrarás:
database/migrations/
├── 0001_01_01_000000_create_users_table.php
├── 0001_01_01_000001_create_cache_table.php
└── 0001_01_01_000002_create_jobs_table.php
El nombre del archivo incluye una marca de
tiempo que determina el orden de ejecución. La
primera migración crea la tabla
users.
Ejecutar migraciones
Para ejecutar todas las migraciones pendientes,
usa el comando migrate:
php artisan migrate
Laravel crea una tabla especial llamada
migrations para registrar qué
migraciones ya se han ejecutado. Así evita
ejecutar la misma migración dos veces.
Para ver el estado de las migraciones sin ejecutarlas:
php artisan migrate:status
Crear una migración
Para crear una nueva migración, usa
make:migration:
php artisan make:migration create_posts_table
El nombre debe describir el cambio:
create_posts_table,
add_status_to_orders_table,
drop_legacy_users_table.
Si el nombre contiene create_ y
_table, Laravel genera
automáticamente el código para crear una tabla:
<?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::create('posts', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
El método up() define los cambios a
aplicar. El método down() define
cómo revertirlos.
Tipos de columnas
El objeto Blueprint proporciona
métodos para definir columnas. Estos son los
tipos más comunes:
<?php
Schema::create('posts', function (Blueprint $table) {
// Clave primaria autoincremental
$table->id();
// Textos
$table->string('title'); // VARCHAR(255)
$table->string('slug', 100); // VARCHAR con longitud
$table->text('content'); // TEXT (textos largos)
// Números
$table->integer('views'); // INT
$table->unsignedInteger('likes'); // INT sin negativos
$table->decimal('price', 8, 2); // DECIMAL(8,2) para dinero
// Booleanos y fechas
$table->boolean('is_published'); // BOOLEAN
$table->date('published_at'); // DATE
$table->dateTime('scheduled_at'); // DATETIME
$table->timestamp('verified_at'); // TIMESTAMP
// Timestamps automáticos (created_at, updated_at)
$table->timestamps();
});
Modificadores de columnas
Puedes encadenar modificadores para ajustar el comportamiento de las columnas:
<?php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
// Permitir NULL
$table->string('subtitle')->nullable();
// Valor por defecto
$table->boolean('is_published')->default(false);
$table->integer('views')->default(0);
// Valor único (no repetido)
$table->string('slug')->unique();
// Comentario en la columna
$table->string('status')->comment('draft, published, archived');
$table->timestamps();
});
Claves foráneas
Para relacionar tablas, usa claves foráneas. El
método foreignId() crea una columna
y la referencia:
<?php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
// Clave foránea a la tabla users
$table->foreignId('user_id')->constrained();
// Con opciones de eliminación
$table->foreignId('category_id')
->constrained()
->onDelete('cascade');
$table->timestamps();
});
El método constrained() asume que
la tabla es users (del nombre
user_id). Si el nombre es
diferente, especifícalo:
<?php
$table->foreignId('author_id')->constrained('users');
La tabla referenciada debe existir antes
de crear la clave foránea. Asegúrate de
que la migración de
users se ejecute antes que
la de posts.
Modificar tablas existentes
Para modificar una tabla existente, crea una nueva migración:
php artisan make:migration add_excerpt_to_posts_table
Usa Schema::table() en lugar de
Schema::create():
<?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('posts', function (Blueprint $table) {
$table->string('excerpt', 500)->nullable()->after('title');
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('excerpt');
});
}
};
El modificador after() especifica
la posición de la columna (solo en MySQL).
Revertir migraciones
Si necesitas deshacer la última migración, usa
rollback:
# Revertir el último lote de migraciones
php artisan migrate:rollback
# Revertir las últimas 3 migraciones
php artisan migrate:rollback --step=3
Para eliminar todas las tablas y volver a ejecutar las migraciones:
# Eliminar todas las tablas y migrar de nuevo
php artisan migrate:fresh
Este comando borra todas las tablas y sus datos. Úsalo solo en desarrollo, nunca en producción.
Índices
Los índices mejoran el rendimiento de las consultas. Añádelos a columnas que uses frecuentemente en búsquedas:
<?php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique(); // Índice único
$table->string('status')->index(); // Índice simple
$table->foreignId('user_id')->constrained();
// Índice compuesto
$table->index(['status', 'created_at']);
$table->timestamps();
});
Ejemplo completo
Veamos una migración completa para una tabla de artículos de blog:
<?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::create('articles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->string('slug')->unique();
$table->string('excerpt', 500)->nullable();
$table->text('content');
$table->string('featured_image')->nullable();
$table->boolean('is_published')->default(false);
$table->timestamp('published_at')->nullable();
$table->unsignedInteger('views')->default(0);
$table->timestamps();
$table->index(['is_published', 'published_at']);
});
}
public function down(): void
{
Schema::dropIfExists('articles');
}
};
Ejercicios
Ejercicio 1: Crear tabla de productos
Crea una migración para una tabla
products con: id, name (string),
description (text, nullable), price (decimal con
2 decimales), stock (entero, por defecto 0),
is_active (booleano, por defecto true) y
timestamps.
Ver solución
# Crear la migración
php artisan make:migration create_products_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::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 10, 2);
$table->unsignedInteger('stock')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('products');
}
};
# Ejecutar la migración
php artisan migrate
Ejercicio 2: Añadir columna a tabla existente
Crea una migración para añadir una columna
sku (string, único) a la tabla
products. La columna debe ir
después de name.
Ver solución
# Crear la migración
php artisan make:migration add_sku_to_products_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) {
$table->string('sku')->unique()->after('name');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('sku');
});
}
};
Ejercicio 3: Tabla con clave foránea
Crea una migración para una tabla
reviews que tenga: id, user_id
(clave foránea a users), product_id (clave
foránea a products), rating (entero del 1 al 5),
comment (text, nullable) y timestamps. Ambas
claves foráneas deben eliminar las reviews si se
elimina el usuario o producto.
Ver solución
# Crear la migración
php artisan make:migration create_reviews_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::create('reviews', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained()
->onDelete('cascade');
$table->foreignId('product_id')
->constrained()
->onDelete('cascade');
$table->unsignedTinyInteger('rating');
$table->text('comment')->nullable();
$table->timestamps();
// Un usuario solo puede dejar una review por producto
$table->unique(['user_id', 'product_id']);
});
}
public function down(): void
{
Schema::dropIfExists('reviews');
}
};
Resumen
- Las migraciones definen la estructura de la base de datos con código PHP
-
Se crean con
php artisan make:migration nombre_descriptivo -
up()aplica cambios,down()los revierte -
php artisan migrateejecuta las migraciones pendientes -
Schema::create()crea tablas,Schema::table()las modifica -
Usa modificadores como
nullable(),default(),unique() -
foreignId()->constrained()crea claves foráneas -
migrate:rollbackrevierte,migrate:freshreinicia todo
¿Has encontrado un error o tienes una sugerencia para mejorar esta lección?
Escríbenos¿Te está gustando el curso?
Tenemos cursos premium con proyectos reales, soporte personalizado y certificado.
Descubrir cursos premium