Database Migrations

Last updated: June 29th 2026

Overview

Migrations are like version control for your database. They allow you to define and share your database schema using PHP classes instead of raw SQL files. Migrations work with both MySQL and SQLite.

Creating a Migration

Use the CLI to generate a migration file:

$ php cli make:migration create_users_table

This creates a file in database/migrations/ with a timestamp prefix, e.g. 2024_01_01_120000_create_users_table.php.

The migration file contains an anonymous class extending Migration:


use Simple\Database\Migrations\Migration;

return new class extends Migration {
    public function up(): void
    {
        $this->schema()->create('users', function ($table) {
            $table->id();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        $this->schema()->dropIfExists('users');
    }
};

Writing Migrations

Each migration must implement two methods:

  • up() — runs when the migration is applied. Use $this->schema() to access the Schema Builder.
  • down() — reverses the migration (used when rolling back).

The Schema Builder provides a fluent API for creating and modifying tables:


public function up(): void
{
    $this->schema()->create('posts', function ($table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->onDelete('cascade');
        $table->string('title');
        $table->text('body');
        $table->timestamps();
        $table->softDeletes();
    });
}

Running Migrations

Apply all pending migrations:

$ php cli migrate

This runs any migration files in database/migrations/ that have not yet been applied. A migrations table tracks which migrations have been run.

Migration Status

View the status of all migration files (which have run and which are pending):

$ php cli migrate:status

Output:


  Migration                                    Status    Batch
  2024_01_01_000001_create_users_table.php     Ran       1
  2024_01_01_000002_create_posts_table.php     Pending

Fresh Migrate

Drop all tables and re-run every migration from scratch:

$ php cli migrate:fresh

This is useful during development when you want to rebuild your entire database schema. All user tables are dropped and all migrations are re-applied in order.

Available Column Types

The schema builder blueprint offers a variety of methods that correspond to the different types of columns you can add to your database tables. Call these inside the closure passed to $this->schema()->create() or $this->schema()->table().

bigIncrements

Creates an auto-incrementing UNSIGNED BIGINT (primary key) equivalent column.

$table->bigIncrements('id');

bigInteger

Creates a BIGINT equivalent column.

$table->bigInteger('votes');

binary

Creates a BLOB equivalent column.

$table->binary('photo');

boolean

Creates a BOOLEAN equivalent column.

$table->boolean('confirmed');

char

Creates a CHAR equivalent column with a given length.

$table->char('name', 100);

dateTimeTz

Creates a DATETIME (with timezone) equivalent column with optional precision.

$table->dateTimeTz('created_at', $precision = 0);

dateTime

Creates a DATETIME equivalent column with optional precision.

$table->dateTime('created_at', $precision = 0);

date

Creates a DATE equivalent column.

$table->date('created_at');

decimal

Creates a DECIMAL equivalent column with given precision (total digits) and scale (decimal digits).

$table->decimal('amount', $precision = 8, $scale = 2);

double

Creates a DOUBLE equivalent column with given precision and scale.

$table->double('amount', 8, 2);

enum

Creates an ENUM equivalent column with valid values.

$table->enum('difficulty', ['easy', 'hard']);

float

Creates a FLOAT equivalent column with given precision and scale.

$table->float('amount', 8, 2);

foreignId

Creates an UNSIGNED BIGINT equivalent column (typically used for foreign keys).

$table->foreignId('user_id');

foreignIdFor

Adds a {column}_id equivalent column for a given model class.

$table->foreignIdFor(User::class);

foreignUlid

Creates a ULID equivalent column.

$table->foreignUlid('user_id');

foreignUuid

Creates a UUID equivalent column.

$table->foreignUuid('user_id');

geometry

Creates a GEOMETRY equivalent column.

$table->geometry('positions');

geometryCollection

Creates a GEOMETRYCOLLECTION equivalent column.

$table->geometryCollection('positions');

id

Alias of bigIncrements. Creates an auto-incrementing UNSIGNED BIGINT primary key column. Default column name is id.

$table->id();

increments

Creates an auto-incrementing UNSIGNED INTEGER equivalent column as a primary key.

$table->increments('id');

integer

Creates an INTEGER equivalent column.

$table->integer('votes');

ipAddress

Creates a VARCHAR equivalent column (uses INET on PostgreSQL).

$table->ipAddress('visitor');

json

Creates a JSON equivalent column.

$table->json('options');

jsonb

Creates a JSONB equivalent column.

$table->jsonb('options');

lineString

Creates a LINESTRING equivalent column.

$table->lineString('positions');

longText

Creates a LONGTEXT equivalent column.

$table->longText('description');

macAddress

Creates a column intended to hold a MAC address.

$table->macAddress('device');

mediumIncrements

Creates an auto-incrementing UNSIGNED MEDIUMINT equivalent column as a primary key.

$table->mediumIncrements('id');

mediumInteger

Creates a MEDIUMINT equivalent column.

$table->mediumInteger('votes');

mediumText

Creates a MEDIUMTEXT equivalent column.

$table->mediumText('description');

morphs

Convenience method that adds a {column}_id (UNSIGNED BIGINT) and {column}_type (VARCHAR) column for polymorphic relationships.

$table->morphs('taggable');

multiLineString

Creates a MULTILINESTRING equivalent column.

$table->multiLineString('positions');

multiPoint

Creates a MULTIPOINT equivalent column.

$table->multiPoint('positions');

multiPolygon

Creates a MULTIPOLYGON equivalent column.

$table->multiPolygon('positions');

nullableTimestamps

Alias of timestamps method.

$table->nullableTimestamps(0);

nullableMorphs

Similar to morphs but the columns are created as nullable.

$table->nullableMorphs('taggable');

nullableUlidMorphs

Similar to ulidMorphs but the columns are created as nullable.

$table->nullableUlidMorphs('taggable');

nullableUuidMorphs

Similar to uuidMorphs but the columns are created as nullable.

$table->nullableUuidMorphs('taggable');

point

Creates a POINT equivalent column.

$table->point('position');

polygon

Creates a POLYGON equivalent column.

$table->polygon('position');

rememberToken

Creates a nullable VARCHAR(100) column to store the "remember me" authentication token.

$table->rememberToken();

set

Creates a SET equivalent column with a given list of valid values.

$table->set('flavors', ['strawberry', 'vanilla']);

smallIncrements

Creates an auto-incrementing UNSIGNED SMALLINT equivalent column as a primary key.

$table->smallIncrements('id');

smallInteger

Creates a SMALLINT equivalent column.

$table->smallInteger('votes');

softDeletesTz

Adds a nullable deleted_at TIMESTAMP (with timezone) column for soft deletes.

$table->softDeletesTz($column = 'deleted_at', $precision = 0);

softDeletes

Adds a nullable deleted_at TIMESTAMP column for soft deletes.

$table->softDeletes($column = 'deleted_at', $precision = 0);

string

Creates a VARCHAR equivalent column of the given length.

$table->string('name', 100);

text

Creates a TEXT equivalent column.

$table->text('description');

timeTz

Creates a TIME (with timezone) equivalent column with optional precision.

$table->timeTz('sunrise', $precision = 0);

time

Creates a TIME equivalent column with optional precision.

$table->time('sunrise', $precision = 0);

timestampTz

Creates a TIMESTAMP (with timezone) equivalent column with optional precision.

$table->timestampTz('added_at', $precision = 0);

timestamp

Creates a TIMESTAMP equivalent column with optional precision.

$table->timestamp('added_at', $precision = 0);

timestampsTz

Creates created_at and updated_at TIMESTAMP (with timezone) columns.

$table->timestampsTz($precision = 0);

timestamps

Creates created_at and updated_at TIMESTAMP columns.

$table->timestamps($precision = 0);

tinyIncrements

Creates an auto-incrementing UNSIGNED TINYINT equivalent column as a primary key.

$table->tinyIncrements('id');

tinyInteger

Creates a TINYINT equivalent column.

$table->tinyInteger('votes');

tinyText

Creates a TINYTEXT equivalent column.

$table->tinyText('notes');

unsignedBigInteger

Creates an UNSIGNED BIGINT equivalent column.

$table->unsignedBigInteger('votes');

unsignedDecimal

Creates an UNSIGNED DECIMAL equivalent column with optional precision and scale.

$table->unsignedDecimal('amount', $precision = 8, $scale = 2);

unsignedInteger

Creates an UNSIGNED INTEGER equivalent column.

$table->unsignedInteger('votes');

unsignedMediumInteger

Creates an UNSIGNED MEDIUMINT equivalent column.

$table->unsignedMediumInteger('votes');

unsignedSmallInteger

Creates an UNSIGNED SMALLINT equivalent column.

$table->unsignedSmallInteger('votes');

unsignedTinyInteger

Creates an UNSIGNED TINYINT equivalent column.

$table->unsignedTinyInteger('votes');

ulidMorphs

Convenience method that adds a {column}_id CHAR(26) and {column}_type VARCHAR column for polymorphic relationships using ULID identifiers.

$table->ulidMorphs('taggable');

uuidMorphs

Convenience method that adds a {column}_id CHAR(36) and {column}_type VARCHAR column for polymorphic relationships using UUID identifiers.

$table->uuidMorphs('taggable');

ulid

Creates a ULID equivalent column.

$table->ulid('id');

uuid

Creates a UUID equivalent column.

$table->uuid('id');

year

Creates a YEAR equivalent column.

$table->year('birth_year');

Column Modifiers

In addition to the column types listed above, you may chain column "modifiers" when adding a column:

$table->string('email')->nullable()->default('none');
Modifier Description
->after('column') Place the column "after" another column (MySQL).
->autoIncrement() Set INTEGER columns as auto-incrementing (primary key).
->charset('utf8mb4') Specify a character set for the column (MySQL).
->collation('utf8mb4_unicode_ci') Specify a collation for the column (MySQL/PostgreSQL/SQL Server).
->comment('my comment') Add a comment to a column (MySQL/PostgreSQL).
->default($value) Specify a "default" value for the column.
->first() Place the column "first" in the table (MySQL).
->from($integer) Set the starting value of an auto-incrementing field (MySQL/PostgreSQL).
->invisible() Make the column "invisible" to SELECT * queries (MySQL).
->nullable($value = true) Allow NULL values to be inserted into the column.
->storedAs($expression) Create a stored generated column (MySQL/PostgreSQL).
->unsigned() Set INTEGER columns as UNSIGNED (MySQL).
->useCurrent() Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value.
->useCurrentOnUpdate() Set TIMESTAMP columns to use CURRENT_TIMESTAMP on update (MySQL).
->virtualAs($expression) Create a virtual generated column (MySQL/PostgreSQL/SQLite).
->generatedAs($expression) Create an identity column with sequence options (PostgreSQL).
->always() Defines precedence of sequence values over input for an identity column (PostgreSQL).
->isGeometry() Set spatial column type to geometry (PostgreSQL).

Modifying Columns

The change method allows you to modify the type and attributes of existing columns. For example, to increase the size of a string column:

$this->schema()->table('users', function ($table) {
    $table->string('name', 50)->change();
});

When modifying a column, you must explicitly include all modifiers you want to retain:

$this->schema()->table('users', function ($table) {
    $table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});

SQLite Note

If you are using SQLite, the doctrine/dbal package is required to modify columns. Run composer require doctrine/dbal to install it.

Renaming Columns

To rename a column, use the renameColumn method:

$this->schema()->table('users', function ($table) {
    $table->renameColumn('from', 'to');
});

Dropping Columns

To drop a column, use the dropColumn method:

$this->schema()->table('users', function ($table) {
    $table->dropColumn('votes');
});

You may drop multiple columns at once:

$this->schema()->table('users', function ($table) {
    $table->dropColumn(['votes', 'avatar', 'location']);
});

Convenience methods for dropping common column types:

Method Description
$table->dropMorphs('morphable') Drop the morphable_id and morphable_type columns.
$table->dropRememberToken() Drop the remember_token column.
$table->dropSoftDeletes() Drop the deleted_at column.
$table->dropTimestamps() Drop the created_at and updated_at columns.