Laravel #\[Refreshes\]: Load Generated Columns After Save | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Auto-Load Generated Columns After Save with Laravel's #\[Refreshes\] Attribute        On this page       1. [  The Problem: Stale Models After a Write ](#the-problem-stale-models-after-a-write)
2. [  The Fix: #\[Refreshes\] in Laravel 13.33 ](#the-fix-refreshes-in-laravel-1333)
3. [  Multiple Columns ](#multiple-columns)
4. [  Property-Based Configuration ](#property-based-configuration)
5. [  Generated Values in Model Events ](#generated-values-in-model-events)
6. [  Which Write Methods Trigger a Refresh ](#which-write-methods-trigger-a-refresh)
7. [  How the Refresh Query Works ](#how-the-refresh-query-works)
8. [  \#\[Refreshes\] vs. refresh() ](#refreshes-vs-refresh)
9. [  Key Takeaways ](#key-takeaways)

  ![Auto-Load Generated Columns After Save with Laravel's #[Refreshes] Attribute](https://cdn.msaied.com/697/2450936023128760d64547a61ee24087.png)

 [  Laravel ](https://msaied.com/articles?category=laravel) [  Tips &amp; Tricks ](https://msaied.com/articles?category=tips-tricks)  #Laravel   #Eloquent   #Generated Columns   #Laravel 13   #PHP Attributes  

 Auto-Load Generated Columns After Save with Laravel's #\[Refreshes\] Attribute 
================================================================================

     23 Sep 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said  

       Table of contents

  9 sections  

1. [  01   The Problem: Stale Models After a Write  ](#the-problem-stale-models-after-a-write)
2. [  02   The Fix: #\[Refreshes\] in Laravel 13.33  ](#the-fix-refreshes-in-laravel-1333)
3. [  03   Multiple Columns  ](#multiple-columns)
4. [  04   Property-Based Configuration  ](#property-based-configuration)
5. [  05   Generated Values in Model Events  ](#generated-values-in-model-events)
6. [  06   Which Write Methods Trigger a Refresh  ](#which-write-methods-trigger-a-refresh)
7. [  07   How the Refresh Query Works  ](#how-the-refresh-query-works)
8. [  08   #\[Refreshes\] vs. refresh()  ](#refreshes-vs-refresh)
9. [  09   Key Takeaways  ](#key-takeaways)

       The Problem: Stale Models After a Write
---------------------------------------

When your database schema uses generated columns — columns whose value the database engine computes from other columns — Eloquent does not know about the result after a write. You get `null` on a freshly created model, and a stale value after an update.

Consider an `orders` table where `total` is a stored generated column:

```php
Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->decimal('subtotal', 10, 2);
    $table->decimal('tax', 10, 2);
    $table->decimal('total', 10, 2)->storedAs('subtotal + tax');
    $table->timestamps();
});

```

Before Laravel 13.33, reading `total` right after a write returned nothing useful:

```php
$order = Order::create(['subtotal' => 100, 'tax' => 8.25]);
$order->total; // null

$order->update(['tax' => 9.00]);
$order->total; // still null

```

The only workaround was calling `$order->refresh()` manually after each write, which reloads every column and every loaded relationship — more work than you usually need.

The Fix: #\[Refreshes\] in Laravel 13.33
----------------------------------------

Laravel 13.33 ships the `#[Refreshes]` PHP attribute (contributed by Caleb White in PR #61523). Add it to your model and list the columns the database computes:

```php
use Illuminate\Database\Eloquent\Attributes\Refreshes;
use Illuminate\Database\Eloquent\Model;

#[Refreshes('total')]
class Order extends Model
{
    protected $fillable = ['subtotal', 'tax'];
}

```

After each insert or update, Eloquent runs a targeted `SELECT` for those columns and copies the values onto the model instance:

```php
$order = Order::create(['subtotal' => 100, 'tax' => 8.25]);
$order->total; // "108.25"

$order->update(['tax' => 9.00]);
$order->total; // "109.00"

```

### Multiple Columns

Pass an array or several arguments — both forms are equivalent:

```php
#[Refreshes(['total', 'slug'])]
#[Refreshes('total', 'slug')]

```

### Property-Based Configuration

If you prefer model properties over PHP attributes, use `$refreshes` instead:

```php
class Order extends Model
{
    protected array $refreshes = ['total'];
}

```

When both are present, the property wins and the attribute is ignored. A model with neither runs no extra query.

Generated Values in Model Events
--------------------------------

The refresh runs **after** the `INSERT` or `UPDATE` but **before** Eloquent fires `created` or `updated`. Observers and listeners therefore see the database-computed value immediately:

```php
class OrderObserver
{
    public function created(Order $order): void
    {
        Mail::to($order->customer)->send(new OrderReceipt($order));
    }

    public function updated(Order $order): void
    {
        if ($order->wasChanged('total')) {
            $order->customer->notify(new OrderTotalChanged($order));
        }
    }
}

```

The `wasChanged('total')` check works because Eloquent records the change after the refresh, even though your application code never set `total` directly.

Which Write Methods Trigger a Refresh
-------------------------------------

- **Inserts:** `create()`, `save()`, `saveQuietly()`, `saveOrIgnore()`
- **Updates:** `update()`, `save()`, `saveQuietly()`
- **Increment/decrement:** `increment()`, `decrement()`, `incrementEach()`, `decrementEach()`

How the Refresh Query Works
---------------------------

Eloquent issues a single `SELECT` scoped to the model's primary key:

```sql
select `total` from `orders` where `id` = ? limit 1

```

A few important details:

- The query runs on the **write connection**, so read-replica lag is not a concern.
- Global scopes (soft deletes, tenant scopes) are **skipped**, so the row is always found.
- It uses `firstOrFail()` — if the row has been deleted between the write and the refresh, a `ModelNotFoundException` is thrown.

\#\[Refreshes\] vs. refresh()
-----------------------------

| Scenario | Use | |---|---| | Always need a generated column after every write | `#[Refreshes]` | | Need the full row or relationships reloaded | `$model->refresh()` | | One-off write where adding the attribute would penalise every other save | `$model->refresh()` |

Key Takeaways
-------------

- `#[Refreshes]` was introduced in Laravel 13.33 and eliminates the need to call `refresh()` just to read database-generated column values.
- It adds exactly one `SELECT` per write, limited to the columns you list.
- Model events (`created`, `updated`) fire after the refresh, so listeners always see the computed value.
- The `$refreshes` property alternative is available for teams that avoid PHP attributes on models.
- Use `$model->refresh()` when you need the entire row or loaded relationships reloaded.

---

*Source: [Eloquent Refreshes: Load Generated Columns After Save — Laravel News](https://laravel-news.com/eloquent-refreshes-attribute)*

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Fauto-load-generated-columns-after-save-with-laravels-refreshes-attribute&text=Auto-Load+Generated+Columns+After+Save+with+Laravel%27s+%23%5BRefreshes%5D+Attribute) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Fauto-load-generated-columns-after-save-with-laravels-refreshes-attribute) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Does #\[Refreshes\] work with virtual (non-stored) generated columns?        Yes. The attribute is designed for any column whose value the database sets, including both stored (`storedAs`) and virtual (`virtualAs`) generated columns, as well as values set by database triggers or defaults that Eloquent does not manage. 

      Q02  Will #\[Refreshes\] cause problems when using read replicas?        The refresh query runs on the write connection, not a read replica, so replication lag does not affect it. The query always targets the server where the row was just written. 

      Q03  What happens if I declare both the #\[Refreshes\] attribute and the $refreshes property on the same model?        The $refreshes property takes precedence and the PHP attribute is ignored. A model with neither defined runs no extra query after writes. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Laravel AI SDK 1.0: Classification, Tool Approvals, and Vercel Chat Streaming](https://cdn.msaied.com/696/4a8dc0443e01d9ddfd47cae8515f2943.png) Laravel AI SDK Classification Tool Approvals 

### Laravel AI SDK 1.0: Classification, Tool Approvals, and Vercel Chat Streaming

Laravel AI SDK 1.0 ships a new Classification capability, human-in-the-loop tool approvals, Vercel Chat and AG...

  ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said 

 23 Sep 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-ai-sdk-10-classification-tool-approvals-and-vercel-chat-streaming) [ ![What's New in Laravel 13.33: Tagged Memoized Cache, Model Refreshes, and More](https://cdn.msaied.com/695/68465c4a316f52e811ca17f35812522d.png) Laravel Laravel 13 Eloquent 

### What's New in Laravel 13.33: Tagged Memoized Cache, Model Refreshes, and More

Laravel 13.33 ships tagged support for the memoized cache store, a #\[Refreshes\] model attribute for generated...

  ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said 

 22 Sep 2026     3 min read  

  Read    

 ](https://msaied.com/articles/whats-new-in-laravel-1333-tagged-memoized-cache-model-refreshes-and-more) [ ![Laravel Live Denmark 2026 Talks Are Now on YouTube](https://cdn.msaied.com/694/ef171df318406f98f554df18e58af625.png) Laravel PHP Conference 

### Laravel Live Denmark 2026 Talks Are Now on YouTube

All 17 talks from Laravel Live Denmark 2026 are now on YouTube. The playlist covers PHP generics, Inertia, Nat...

  ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said 

 22 Sep 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-live-denmark-2026-talks-are-now-on-youtube) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
