How and When to use to Use fresh() vs. refresh() in Laravel
If you have worked with Laravel Eloquent for a while, you’ve probably run into a situation where your database data changed, but your $user or $post variable in PHP was still holding onto old data.
To fix this, Laravel gives us two very handy methods: fresh() and refresh().
Initially, both sounds like they do the exact same thing. They reload your model from the database. But under the hood, they work differently, and using the wrong one can cause potential bugs or waste extra memory.
So in this blog we will understand step-by-step breakdown of how they work, why they are necessary, and when to use which.
The Problem: Out-of-Sync Model Variables
When you fetch a model from the database, Eloquent creates a PHP object in memory. If something updates that database row later in your code—like a background queue job, a database trigger, a raw SQL query, or an HTTP API callback—your PHP object doesn't know about it automatically.
$user = User::find(1);
echo $user->status; // Outputs: 'pending'
// Imagine a background process or raw SQL updates the database directly
DB::table('users')->where('id', 1)->update(['status' => 'active']);
// Your PHP object is out of sync!
echo $user->status; // Still outputs: 'pending'
To get the latest active status from the database, you need to reload the model. This is where fresh() and refresh() come in.
1. The fresh() Method
The fresh() method runs a brand-new SELECT query in the database and returns a completely new instance of the model. Your original variable stays untouched until and unless you reassign it.
$user = User::find(1);
// Creates a BRAND NEW model instance with fresh data from the DB
$freshUser = $user->fresh();
echo $user->status; // Output: 'pending' (Original variable stays unchanged)
echo $freshUser->status; // Output: 'active' (New instance has fresh data)
If you want your original variable to update using fresh(), you must explicitly reassign it:
$user = $user->fresh();
Note:
If the record was deleted from the database in the meantime, $user->fresh() will simply return null.
2. The refresh() Method
The refresh() method re-queries the database and mutates (updates) the existing model instance in place. It does not return a new object, it modifies your current variable directly and updates all loaded relationships.
$user = User::find(1);
// Updates the existing $user object in memory directly
$user->refresh();
echo $user->status; // Output: 'active'
Note:
refresh() also reloads any loaded relationships on that model so that your relational data stays synchronized too.
$user = User::with('posts')->find(1);
// Someone adds a new post to this user in the database...
$user->refresh();
// $user->posts now includes the newly added post automatically!
Real-World Example: Why This Matters in Testing
One of the most common places you will use these methods is inside your Pest or PHPUnit automated tests.
Suppose you are testing an endpoint that marks an order as "shipped" and updates its timestamp.
test('order status can be updated to shipped', function () {
$order = Order::factory()->create(['status' => 'pending']);
// Make an HTTP POST request to your API controller
$this->postJson("/api/orders/{$order->id}/ship");
// THIS WILL FAIL! $order in memory still says 'pending'
// expect($order->status)->toBe('shipped');
// FIX: Reload the existing instance directly
$order->refresh();
expect($order->status)->toBe('shipped');
});
Using $order->refresh() here updates the $order variable in place so your assertion passes cleanly without having to write $order = $order->fresh().
