Laravel Migrations: nullable and constrained - in which order?

When creating the foreign key migrations in Laravel, a short syntax is constrained(). With that, it's easy to make one mistake related to Column modifiers.

If you want that foreign key column to be nullable, which syntax is correct?

1// Option A:
2$table->foreignId('user_id')->nullable()->constrained();
3 
4// Or, Option B:
5$table->foreignId('user_id')->constrained()->nullable();

Perhaps, you would say both?

Wrong.

On the official documentation page for the foreign keys, you may find this important sentence:

Any additional column modifiers must be called before the constrained method.

Yes, nullable() is one of the so-called column modifiers. So yeah, the correct way is nullable before constrained.

But wait, what happens if we put it the other way around?

1Schema::create('tasks', function (Blueprint $table) {
2 $table->id();
3 $table->string('name');
4 $table->foreignId('user_id')->constrained()->nullable(); //INCORRECT!
5 $table->timestamps();
6});

Would it throw an error? Not quite.

In fact, the migration will actually succeed.

That's what makes this mistake so dangerous: you may not even notice it.

You will have an issue only when saving the data:

1Task::create(['name' => 'Testing']);
2 
3// Will throw this:
4Illuminate\Database\QueryException with message 'SQLSTATE[HY000]:
5General error: 1364 Field 'user_id' doesn't have a default value
6 (SQL: insert into `tasks` (`name`, `updated_at`, `created_at`)
7 values (Testing, 2022-10-05 11:48:05, 2022-10-05 11:48:05))'

So, be careful and don't forget to add nullable before constrained.

In fact, it's also applicable to any other column modifiers. A few typical examples:

  • ->after('name')->constrained(); and not ->constrained()->after('name');
  • ->default(1)->constrained(); and not ->constrained()->default(1);
  • ->comment('Some comment')->constrained(); and not ->constrained()->comment('Some comment');
avatar

is there a way can solve this? like using phpstan?

avatar

Why does this error happen? Is the field not nullable anymore, or is the change more subtle?

Like our articles?

Become a Premium Member for $129/year or $29/month

Written by

You might also like