Laravel Reference
Defining a migration
See the Artisan commands guide for more on make: generators like the one below.
php artisan make:migration create_posts_table
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->text('body');
$table->boolean('published')->default(false);
$table->timestamps();
});
php artisan migrate
Common column types
| Method | SQL type / purpose |
|---|---|
id() | Auto-incrementing BIGINT UNSIGNED primary key named id. |
foreignId('user_id') | BIGINT UNSIGNED sized to match id(), for foreign keys. |
string('name', 255) | VARCHAR, default length 255. |
text('body') | TEXT — longer, unbounded content. |
longText('content') | LONGTEXT for very large content. |
integer('votes') | Standard signed INT. |
unsignedInteger('votes') | Unsigned INT — no negative values. |
bigInteger('views') | Signed BIGINT. |
tinyInteger('flag') | Small integer, often used for compact enums/flags. |
boolean('active') | TINYINT(1), cast to PHP bool. |
decimal('price', 8, 2) | Fixed-precision decimal — use for money, never float. |
float('rating', 8, 2) / double(...) | Floating-point numbers — approximate, avoid for currency. |
date('published_on') | Date only, no time component. |
dateTime('published_at') | Date and time, no timezone awareness. |
timestamp('verified_at') | Like dateTime, but with timezone-related database behaviour. |
timestamps() | Adds nullable created_at and updated_at timestamp columns. |
softDeletes() | Adds a nullable deleted_at column for the SoftDeletes trait. |
json('metadata') | Native JSON column, pairs with an Eloquent array/object cast (inspect one with the JSON viewer). |
uuid('external_id') | CHAR(36) for storing a UUID string (generate one with the UUID generator). |
enum('status', [...]) | Restricts the column to a fixed list of string values. |
foreignIdFor(Model::class) | Adds a foreign key column named after the given model. |
morphs('commentable') | Adds commentable_id + commentable_type for an Eloquent polymorphic relationship. |
nullableMorphs(...) / ulidMorphs(...) | Same as morphs(), but nullable, or using a ULID instead of a numeric ID. |
Two related helpers don't add a normal column at all: storedAs('price * qty') (or virtualAs(...)) defines a generated column computed from other columns by the database itself, and $table->fullText('body') adds a full-text index for whereFullText() search queries.
Column modifiers
Chain these onto most column definitions to adjust their behaviour:
| Modifier | Effect |
|---|---|
nullable() | Allows NULL to be stored (columns are NOT NULL by default). |
default($value) | Sets a default value used when none is provided on insert. |
unsigned() | Disallows negative values on numeric columns. |
unique() | Adds a unique index on the column. |
index() | Adds a plain (non-unique) index for faster lookups. |
$table->unique(['a', 'b']) | Composite unique constraint across multiple columns — called on the table, not chained onto one column. |
$table->index(['a', 'b']) | Composite (multi-column) index, same call style as above. |
comment('...') | Attaches a comment to the column in the database schema. |
after('column') | Positions the column after another (MySQL only). |
useCurrent() | Defaults a timestamp column to CURRENT_TIMESTAMP. |
Foreign keys
$table->foreignId('user_id')
->constrained() // references users.id by convention
->cascadeOnDelete(); // or ->nullOnDelete(), ->restrictOnDelete()
// Explicit form
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
Modifying an existing table
Schema::table('posts', function (Blueprint $table) {
$table->string('slug')->after('title')->nullable();
});
// Requires doctrine/dbal on older Laravel versions; built in on recent ones
Schema::table('posts', function (Blueprint $table) {
$table->renameColumn('body', 'content');
});
// Dropping things — the counterpart to adding them above
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('slug');
$table->dropForeign(['user_id']); // or ->dropForeign('posts_user_id_foreign')
$table->dropIndex(['title']);
$table->dropUnique(['email']);
});
Newer migrations are commonly generated without a wrapping class name at all — an anonymous class returned directly from the file, which is now the default from make:migration and avoids class name collisions between two migrations that both touch, say, a posts table. Passing --create=posts or --table=posts to make:migration pre-fills the Schema::create/Schema::table boilerplate shown throughout this page, based on naming convention alone (create_posts_table is detected as a create migration automatically).