Laravel 14: Eloquent defaults() Method Explained | 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)    Laravel 14 Adds a defaults() Method to Eloquent Models        On this page       1. [  Laravel 14 Brings a defaults() Method to Eloquent Models ](#laravel-14-brings-a-codedefaultscode-method-to-eloquent-models)
2. [  The Problem with $attributes ](#the-problem-with-codeattributescode)
3. [  The defaults() Method in Laravel 14 ](#the-codedefaultscode-method-in-laravel-14)
4. [  Merge Priority ](#merge-priority)
5. [  Raw Values Only ](#raw-values-only)
6. [  When defaults() Runs ](#when-codedefaultscode-runs)
7. [  Upgrading: Check for Name Conflicts ](#upgrading-check-for-name-conflicts)
8. [  Key Takeaways ](#key-takeaways)

  ![Laravel 14 Adds a defaults() Method to Eloquent Models](https://cdn.msaied.com/725/6d4daa85070ffb81d6a9a3e25a8ed08c.png)

 [  Laravel ](https://msaied.com/articles?category=laravel)  #Laravel 14   #Eloquent   #Model Defaults   #PHP   #Feature Flags  

 Laravel 14 Adds a defaults() Method to Eloquent Models 
========================================================

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

       Table of contents

1. [  01   Laravel 14 Brings a defaults() Method to Eloquent Models  ](#laravel-14-brings-a-codedefaultscode-method-to-eloquent-models)
2. [  02   The Problem with $attributes  ](#the-problem-with-codeattributescode)
3. [  03   The defaults() Method in Laravel 14  ](#the-codedefaultscode-method-in-laravel-14)
4. [  04   Merge Priority  ](#merge-priority)
5. [  05   Raw Values Only  ](#raw-values-only)
6. [  06   When defaults() Runs  ](#when-codedefaultscode-runs)
7. [  07   Upgrading: Check for Name Conflicts  ](#upgrading-check-for-name-conflicts)
8. [  08   Key Takeaways  ](#key-takeaways)

 Laravel 14 Brings a `defaults()` Method to Eloquent Models
----------------------------------------------------------

Eloquent models have long used the `$attributes` property to define default column values. It works well for static values, but PHP only permits constant expressions in property defaults — meaning you cannot call `config()`, `now()`, or check a feature flag there. Laravel 14 solves this cleanly with a new `defaults()` method.

The feature was contributed by [Jack Bayliss](https://github.com/jackbayliss) in [PR #61688](https://github.com/laravel/framework/pull/61688) and is merged into the `master` branch. It may still change before Laravel 14 is officially released.

---

The Problem with `$attributes`
------------------------------

When default values depend on runtime state — a feature flag, a config value, or the current timestamp — developers had to override `__construct()` to apply them:

```php
class Subscription extends Model
{
    protected $attributes = [
        'cancelled' => false,
        'trial_days' => 14,
    ];

    public function __construct(array $attributes = [])
    {
        if (Feature::active('extended-trials')) {
            $this->attributes['trial_days'] = 30;
        }

        parent::__construct($attributes);
    }
}

```

This works, but it is boilerplate that clutters the model and is easy to get wrong (calling `parent::__construct()` at the wrong point, for example).

---

The `defaults()` Method in Laravel 14
-------------------------------------

In Laravel 14 you move that logic into a dedicated `defaults()` method:

```php
class Subscription extends Model
{
    protected function defaults(): array
    {
        return [
            'cancelled'  => false,
            'trial_days' => Feature::active('extended-trials') ? 30 : 14,
            'expires_at' => now()->addDays(config('billing.grace_period'))->toDateTimeString(),
        ];
    }
}

```

Instantiating the model now reflects the runtime state automatically:

```php
$subscription = new Subscription;
$subscription->trial_days; // 30 when the flag is active, 14 otherwise

```

---

Merge Priority
--------------

The constructor applies values in a predictable order:

1. `$attributes` property values are set first.
2. `defaults()` is merged over them — it wins when both define the same key.
3. Values passed to `new`, `create()`, or `fill()` are applied last and win over both.

```php
$subscription = Subscription::create(['trial_days' => 60]);
$subscription->trial_days; // 60

```

Defaults are merged before the model syncs its original attributes, so they are **not** treated as dirty changes. They are still written to the database on insert, just like `$attributes`.

---

Raw Values Only
---------------

Like `$attributes`, values returned from `defaults()` are **raw** — they bypass casts and mutators. Return the value exactly as it should be stored in the database:

```php
protected function defaults(): array
{
    return [
        // Column cast to `array` expects a JSON string
        'settings'   => json_encode(['theme' => 'light']),
        // Date column
        'expires_at' => now()->addDays(30)->toDateTimeString(),
    ];
}

```

Returning a PHP array for a JSON-cast column will cause a read error because the cast expects a string.

---

When `defaults()` Runs
----------------------

`defaults()` is called every time a model instance is constructed — including rows loaded from the database. Eloquent builds each retrieved row with a new model instance, so `defaults()` runs once per row before the database values replace the defaults.

---

Upgrading: Check for Name Conflicts
-----------------------------------

Because an existing model might already have a method named `defaults()`, Laravel 14 targets this as a breaking change. Before upgrading, scan your models:

```bash
grep -rn "function defaults" app/Models

```

Rename any method that is not intended to return default attribute values.

---

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

- `defaults()` replaces constructor hacks for dynamic Eloquent default attributes.
- It supports any PHP expression: `config()`, `now()`, feature flags, etc.
- Values are **raw** — no casts or mutators are applied.
- Explicitly passed attributes always win over `defaults()`.
- Run `grep -rn "function defaults" app/Models` before upgrading to avoid conflicts.
- The feature is merged but may change before Laravel 14 ships.

---

*Source: [Laravel 14 Adds a defaults() Method to Eloquent Models — Laravel News](https://laravel-news.com/laravel-model-defaults)*

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-14-adds-a-defaults-method-to-eloquent-models&text=Laravel+14+Adds+a+defaults%28%29+Method+to+Eloquent+Models) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-14-adds-a-defaults-method-to-eloquent-models) 

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

  3 questions  

     Q01  What is the difference between $attributes and defaults() in Laravel 14 Eloquent models?        $attributes only accepts constant PHP expressions, so you cannot use config(), now(), or feature flags there. The defaults() method runs at construction time and accepts any PHP expression, making it suitable for dynamic default values. 

      Q02  Do values from defaults() go through Eloquent casts or mutators?        No. Like $attributes, values returned from defaults() are raw and bypass casts and mutators. You must return the value in the exact format the database column expects — for example, a JSON string for a column cast to array. 

      Q03  What should I do before upgrading to Laravel 14 if I already have a defaults() method on a model?        Run `grep -rn "function defaults" app/Models` to find any existing defaults() methods. Rename any method that is not intended to return default attribute values, because Laravel 14's constructor will call defaults() and merge its return value into the model's attributes. 

  Continue reading

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

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

 [ ![Laravel AI SDK and Laravel MCP Security Fixes: Update Now](https://cdn.msaied.com/722/fbe8df92faa32e9b9cee984a18bd4411.png) security laravel-ai laravel-mcp 

### Laravel AI SDK and Laravel MCP Security Fixes: Update Now

Two security advisories were published for laravel/ai and laravel/mcp on September 30, 2026. Both are fixed—ru...

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

 30 Sep 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-ai-sdk-and-laravel-mcp-security-fixes-update-now) [ ![Migrating Pinkary from Laravel Forge to Laravel Cloud: An Engineering Playbook](https://cdn.msaied.com/723/6f9c9010ccb06581b52bcfab81e47dd9.png) Laravel Cloud Laravel Forge MySQL 

### Migrating Pinkary from Laravel Forge to Laravel Cloud: An Engineering Playbook

A code-backed walkthrough of the real issues encountered moving Pinkary from Laravel Forge to Laravel Cloud: S...

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

 30 Sep 2026     5 min read  

  Read    

 ](https://msaied.com/articles/migrating-pinkary-from-laravel-forge-to-laravel-cloud-an-engineering-playbook) [ ![PostgreSQL Recursive CTEs in Laravel: Hierarchical Data Without the ORM Gymnastics](https://cdn.msaied.com/720/3e3d256d54dd4036099122e0b035e482.png) laravel postgresql eloquent 

### PostgreSQL Recursive CTEs in Laravel: Hierarchical Data Without the ORM Gymnastics

Recursive CTEs let PostgreSQL walk tree structures in a single query. Learn how to wire them into Laravel's qu...

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

 30 Sep 2026     2 min read  

  Read    

 ](https://msaied.com/articles/postgresql-recursive-ctes-in-laravel-hierarchical-data-without-the-orm-gymnastics) 

   [  ![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)
