Eloquent / Laravel: How to get last insert/update ID/instance of updateOrCreate()?
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Eloquent / Laravel: How to Get the Last Insert/Update ID or Instance of updateOrCreate()
The Eloquent method updateOrCreate() is a powerful tool in Laravel, designed to simplify the common task of either updating an existing record or creating a new one based on a set of conditions. However, as you correctly noted, its return value is strictly boolean (true if a record was updated/created, false otherwise). This leaves developers wanting the actual model instance or the primary key immediately after the operation.
This post will dive into why this limitation exists and provide robust, practical solutions for retrieving the ID or the full Eloquent model following an updateOrCreate() call, ensuring your application logic remains clean and efficient.
Understanding the Limitation of updateOrCreate()
The core reason updateOrCreate() only returns a boolean is that its primary focus is the action (did it succeed?) rather than the result (what was created or updated?). It executes a single atomic operation against the database. To retrieve the resulting record, you must perform a separate query, which introduces potential complexity and performance overhead if not handled carefully.
If we simply relied on re-querying based on the input data, we might end up running two separate queries (one for updateOrCreate and one for fetching), which is exactly what we are trying to avoid in terms of efficiency.
Solution 1: The Idiomatic Approach – Pre-fetching the Model
The most robust and often cleanest way to guarantee you have the resulting model instance or ID is to structure your logic so that the retrieval happens as part of the process, rather than as a separate step. While updateOrCreate() itself doesn't return the model, we can use related methods to achieve the desired outcome elegantly.
If you need the instance, the best practice is often to combine the search and creation logic into a controlled flow:
use App\Models\Product;
$attributes = [
'name' => 'New Product Name',
'price' => 99.99,
];
// 1. Attempt to find the record first (optional but good for context)
$product = Product::where('sku', $attributes['sku'])->first();
if ($product) {
// If found, update it directly
$product->update($attributes);
} else {
// If not found, create it
$product = Product::create($attributes);
}
// Now $product holds the instance or the newly created model.
// You can access the ID easily: $productId = $product->id;While this isn't a direct use of updateOrCreate(), it addresses your core need by ensuring you always possess the object, which is superior to relying on subsequent queries. This philosophy aligns perfectly with how we approach data management in Laravel, promoting clean code and efficient database interaction, much like adhering to best practices outlined by organizations like Laravel Company.
Solution 2: Retrieving the ID After updateOrCreate() (The Direct Fix)
If you are strictly committed to using updateOrCreate(), you must rely on the initial search logic to establish context, or perform an immediate follow-up query based on the conditions provided. Since you know what you were looking for, you can use those same criteria to fetch the result.
Here is how you can combine the operation and retrieval:
use App\Models\User;
$data = [
'username' => 'new_user',
'email' => 'new@example.com',
];
// Attempt the update/create operation
$success = User::updateOrCreate(
['username' => $data['username']], // Conditions to match
$data // Data to set/update
);
if ($success) {
// If successful, retrieve the ID using the criteria we just used.
// This ensures we get the correct ID regardless of which operation succeeded.
$userId = User::where('username', $data['username'])->value('id');
echo "Record successfully updated or created. New ID: " . $userId;
} else {
echo "Operation failed.";
}This approach is more explicit about intent. Although it involves a second query, it makes the flow clearer: first execute the atomic operation, then explicitly fetch the result you need. For complex scenarios involving nested relationships or heavy data, always assess whether separating the operations into sequential steps yields better readability and maintainability.
Conclusion
While updateOrCreate() is excellent for its atomic nature, developers must account for what they need after the action is complete. Relying solely on the boolean return value forces you into secondary queries. By adopting a pattern where you use context to inform your subsequent retrieval (either by pre-fetching or by re-querying based on known criteria), you maintain control over the data flow and ensure that you always have access to the necessary model instance or primary key, leading to more predictable and performant applications.