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?

// Option A:
$table->foreignId('user_id')->nullable()->constrained();
 
// Or, Option B:
$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?

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

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:

Task::create(['name' => 'Testing']);
 
// Will throw this:
Illuminate\Database\QueryException with message 'SQLSTATE[HY000]:
General error: 1364 Field 'user_id' doesn't have a default value
(SQL: insert into `tasks` (`name`, `updated_at`, `created_at`)
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?

avatar

Had this issue. Kept on bringing errors when running migrations. Thanks alot.

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 66 courses (1167 lessons, total 43 h 18 min)
  • 88 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent New Courses