Separate lookup conditions from update attributes when upserting individual Eloquent models.
Instead of writing manual if ($model = Model::find(...)) { $model->update(...); } else { Model::create(...); } logic, Eloquent provides firstOrCreate() and updateOrCreate().
Both methods accept two arrays:
- Lookup Attributes: Columns used in the
WHEREquery to locate an existing record. - Values: Attributes to set or update when creating or modifying the model.
Finding or Creating Records with firstOrCreate()
If a matching record exists, it is returned untouched. If no record exists, it is created using the merged attributes:
use App\Models\User;
// Looks for a user by email. If not found, creates one with the given name and status.
$user = User::firstOrCreate(
['email' => '[email protected]'], // Lookup conditions
['name' => 'Punyapal Shah', 'status' => 'active'] // Additional attributes on create only
);
Upserting Records with updateOrCreate()
If a matching record exists, it is updated with the second array. If not found, a new record is created with all attributes:
use App\Models\Subscription;
$subscription = Subscription::updateOrCreate(
['user_id' => $user->id, 'plan_id' => 'pro_monthly'], // Lookup conditions
['expires_at' => now()->addMonth(), 'is_active' => true] // Attributes to update or create
);
Inspecting Model Creation State
Check whether the returned model was newly created or already existed using wasRecentlyCreated:
if ($subscription->wasRecentlyCreated) {
logger()->info('New subscription created.');
} else {
logger()->info('Existing subscription updated.');
}
Summary
- First argument defines the
WHEREconstraints. - Second argument specifies the values to set or update.
- Use
$model->wasRecentlyCreatedto run event triggers only on newly created records.
Related Tips
View all tips →Refresh and Pessimistically Lock Models with refreshForUpdate() in Laravel 13.27
Laravel 13.27 adds refreshForUpdate(), reloading an existing model instance in-place with fresh database attributes while acquiring an exclusive FOR UPDATE row lock.
Scope Pivot Table Queries with Closures in wherePivot() in Laravel 13.26
Laravel 13.26 allows wherePivot() and orWherePivot() to accept closures, enabling direct reuse of local scopes defined on custom Pivot models.