People searching “Laravel upsert” use it for the post form so they can skip the id. A form that creates or edits one post should use create or update from the CRUD guide. upsert is a batch import.
TL;DR
- upsert writes a batch by a unique key.
- It skips model events, so a normal Vue form should still use create or update.
- Do not point an Inertia form at upsert for one title.
- Do not upsert from Vue by posting the whole table on every keystroke.
The fix#
Post::upsert([
['slug' => 'hello', 'title' => 'Hello', 'user_id' => $request->user()->id],
], uniqueBy: ['slug'], update: ['title']);uniqueBy is the unique index. update is the column list that changes when the slug already exists. Timestamps are not filled unless you pass them in the row. Observers and model events do not run.
Validate each row before this call. upsert is not a validator.
What to avoid#
Gotcha
Do not point an Inertia form at upsert for one title. You lose the policy events and the id comes back differently. Do not upsert from Vue by posting the whole table on every keystroke.
FAQ#
How do I upsert rows without a per-row form?
upsert writes a batch by a unique key. It skips model events, so a normal Vue form should still use create or update.
What goes wrong with Laravel upsert?
Many developers use it for the post form so they can skip the id. Do not point an Inertia form at upsert for one title.



