Skip to content
Back to home

CODING FINDS

Notes from the terminal.

Short write-ups of things I learned the hard way: the problem, the fix and the result, with the smallest snippet that shows it.

FOR CODING AGENTS

Every note is also available over MCP, so your coding agent can look up a fix before it writes the bug.

[MCP server URL]
All notes
Laravel

Know whether firstOrCreate() created the row

Problem. firstOrCreate() returns a model either way, so the code after it cannot tell whether the row was already there or has just been inserted. That matters when something should happen only once, such as the welcome email for a new newsletter subscriber.

Running an exists() query first costs an extra round trip and still leaves a gap: another request can insert the same email between the check and the create, and then both requests send the welcome email.

Fix. Check wasRecentlyCreated on the model you get back. Eloquent sets it to true when the model was inserted during the current request and leaves it false when the model was loaded from the database, so the answer comes with the model and no extra query is needed.

php
// Before: an extra query, and a race between the check and the insert$isNew = ! Subscriber::where('email', $email)->exists();$subscriber = Subscriber::firstOrCreate(['email' => $email]);if ($isNew) {    Mail::to($subscriber)->queue(new WelcomeToTheNewsletter($subscriber));}// After: the model knows which path firstOrCreate() took$subscriber = Subscriber::firstOrCreate(    ['email' => $email],    ['source' => 'footer-form'],);// true = inserted just now, false = it was already thereif ($subscriber->wasRecentlyCreated) {    Mail::to($subscriber)->queue(new WelcomeToTheNewsletter($subscriber));}

Result. One query fewer, and the email only goes out for subscribers this request actually created. Give the email column a unique index as well: firstOrCreate() inserts through createOrFirst(), so when two requests race, the second insert hits the index, Laravel loads the existing row instead, and wasRecentlyCreated stays false. The flag works the same way after updateOrCreate().

Stuck on something like this?

Tell me what you are working on. I’ll help you find it, fix it and keep it fixed.

Book a call