Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

murilo's avatar
Level 10

laravel migration updates

hello , I am trying to update some migrations in a old laravel project . is there any difference between those migrations

this

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('contract_id')->constrained('contracts')->onDelete('cascade');
            $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->dropForeign('contract_id_foreign');
            $table->dropForeign('user_id_foreign');
        });
        Schema::dropIfExists('contracts');
    }
};


and this

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('contract_id')->unsigned()->index();
            $table->foreign('contract_id')->references('id')->on('contracts')->onDelete('cascade');

            $table->bigInteger('user_id')->unsigned()->index();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');


            $table->foreignId('user_id')->constrained('users');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->dropForeign('contracts_contract_id_foreign');
            $table->dropForeign('contracts_user_id_foreign');
        });
        Schema::dropIfExists('contracts');
    }
};

0 likes
1 reply
LaryAI's avatar
Level 58

The two migration examples you provided are functionally similar but have some differences in how they define foreign keys and handle the down method. Let's break down the differences:

First Migration

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('contract_id')->constrained('contracts')->onDelete('cascade');
            $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->dropForeign('contract_id_foreign');
            $table->dropForeign('user_id_foreign');
        });
        Schema::dropIfExists('contracts');
    }
};

Second Migration

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('contract_id')->unsigned()->index();
            $table->foreign('contract_id')->references('id')->on('contracts')->onDelete('cascade');

            $table->bigInteger('user_id')->unsigned()->index();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->dropForeign('contracts_contract_id_foreign');
            $table->dropForeign('contracts_user_id_foreign');
        });
        Schema::dropIfExists('contracts');
    }
};

Key Differences

  1. Foreign Key Definition:

    • First Migration: Uses foreignId with constrained method, which is a more concise and modern way to define foreign keys in Laravel.
    • Second Migration: Uses bigInteger with foreign method, which is a more verbose way to define foreign keys.
  2. Indexing:

    • First Migration: Automatically indexes the foreign keys when using foreignId.
    • Second Migration: Explicitly adds an index using index() method.
  3. Redundant Foreign Key Definition:

    • Second Migration: Has a redundant foreign key definition for user_id. It first defines it using bigInteger and then again using foreignId. This is unnecessary and should be removed.
  4. Dropping Foreign Keys in down Method:

    • First Migration: Uses dropForeign with the foreign key column names.
    • Second Migration: Uses dropForeign with the full foreign key constraint names, which is more precise but requires knowing the exact constraint names.

Recommended Approach

The first migration is more concise and follows modern Laravel conventions. Here is a cleaned-up version of the first migration:

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('contracts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('contract_id')->constrained('contracts')->onDelete('cascade');
            $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('contracts', function (Blueprint $table) {
            $table->dropForeign(['contract_id']);
            $table->dropForeign(['user_id']);
        });
        Schema::dropIfExists('contracts');
    }
};

This version is clean, concise, and follows best practices for defining and dropping foreign keys in Laravel migrations.

Please or to participate in this conversation.