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:
```php
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](https://laravelcompany.com).
## 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:
```php
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.