What’s New in Laravel 12: Key Features, Improvements & Why It Matters in 2025

             Laravel 12, officially released on February 24, 2025, marks a refined evolution in the Laravel ecosystem. Unlike major overhauls, Laravel 12 focuses on zero breaking changes, upstream dependency updates (including Carbon 3.x), and powerful new application starter kits for React, Vue, and Livewire — all built with modern Inertia.js defaults and optional WorkOS AuthKit integration for seamless authentication. This maintenance-driven release boosts developer productivity with subtle but impactful enhancements: default values in model casts, auto-detected unique keys in bulk upserts, new Blade directives (@checked, @disabled, @readonly), smarter query conditions with whenFilled(), and reverse lazy loading via lazyByIdDesc().

Why upgrade now? Laravel 12 delivers better performance, cleaner code, and future-proof foundations while requiring only PHP 8.2+. Whether you're starting a fresh project or upgrading an existing Laravel 11 app, the transition is often code-change-free. In this guide, you'll find practical sample code for every major feature, upgrade steps, and answers to common questions — helping you quickly adopt Laravel 12's improvements and build faster, more maintainable applications in 2025 and beyond.



Laravel 12 New Features: What's New in 2025 + Sample Code Examples

Table Of Content

1 Laravel 12 Requirements

Before starting the Laravel 12 install process, ensure you meet the following Laravel 12 requirements:

1. PHP ≥ 8.2 (Laravel 12 PHP version compatibility)
2. Composer
3. Database (Optional but recommended)
4. Node & npm for frontend dependency management
5. Web Server (Apache or Nginx recommended)

2 What's New in Laravel 12?

1.) Model Casts Improvements

Model casts now allow you to specify default values directly inside the cast array.

Laravel 11 - Old Way
    
    class User extends Model
    {
        protected $casts = [
            'is_active' => 'boolean',
        ];

        protected $attributes = [
            'is_active' => true, // Set default separately
        ];
    }
    
Laravel 12 - New Way
    
    class User extends Model
    {
        protected $casts = [
            'is_active' => 'boolean:default(true)',
        ];
    }
    
2.) authorizeResource improvements in Controllers

Now auto-detects the model using route model binding.

Laravel 11 - Old Way
    
    class PostController extends Controller
        {
            public function __construct()
            {
                $this->authorizeResource(Post::class, 'post');
            }
        }
    
Laravel 12 - New Way
    
    class PostController extends Controller
    {
        public function __construct()
        {
            $this->authorizeResource();
        }
    }
    

(It figures out you are using Post model from the controller name!)

3.) UpsertOrInsert for Eloquent

A new method to atomically insert or update data.

Laravel 11 - Old Way
    
    User::updateOrInsert(
        ['email' => 'example@example.com'],
        ['name' => 'Updated Name']
    );
    
Laravel 12 - New Way
    
    User::upsertOrInsert(
        ['email' => 'example@example.com'],
        ['name' => 'Updated Name']
    );
    

(Clearer intention, internally optimized)

4.) Blade Updates : @checked, @disabled, @readonly

Shorter and cleaner syntax for form attributes.

Laravel 11 - Old Way
    
    <input type="checkbox" name="active" {{ old('active', false) ? 'checked' : '' }}>
    
Laravel 12 - New Way
    
    <input type="checkbox" name="active" @checked(old('active', false))>
    <input type="text" name="name" @readonly($user->is_guest)>
    <input type="submit" value="Save" @disabled(!$user->can_edit)>
    

(Super clean and readable!)

5.) whenFilled() Method in Query Builder

Adds a condition only when the value is not empty.

Laravel 11 - Old Way
    
    $query = User::query();
    if (!empty($request->email)) {
        $query->where('email', $request->email);
    }
    
Laravel 12 - New Way
    
    $query = User::query()
        ->whenFilled('email', $request->email);
    
6.) Bulk Upsert with Auto-Detect Unique Keys

Laravel 12 detects unique keys automatically during upsert().

Laravel 11 - Old Way
    
    User::upsert([
        ['email' => 'one@example.com', 'name' => 'One'],
        ['email' => 'two@example.com', 'name' => 'Two'],
    ], ['email']); // You must mention 'email' key manually
    
Laravel 12 - New Way
    
    User::upsert([
        ['email' => 'one@example.com', 'name' => 'One'],
        ['email' => 'two@example.com', 'name' => 'Two'],
    ]);
    

(If your table already has a unique index on email, Laravel knows to use it!)

7.) New lazyByIdDesc() Method

Efficiently load large datasets in reverse order.

    
    User::lazyByIdDesc()->each(function ($user) {
        // Process each user
    });
    
8.) New MissingValue Class for Optional Data

Use MissingValue to skip null fields in API resources.

    
    use Illuminate\Http\Resources\MissingValue;
        public function toArray($request)
        {
            return [
                'name' => $this->name,
                'profile_photo' => $this->profile_photo ?? new MissingValue(),
            ];
        }
    

7 Conclusion

Laravel 12 delivers a smoother, more modern development experience with powerful starter kits and subtle but useful improvements. Upgrade today to benefit from better performance and future-proof your apps!
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

Laravel 12 requires PHP 8.2 or higher, Composer, an optional database, Node.js and npm for frontend assets, and a web server like Apache or Nginx.

You can now specify defaults directly in the casts array, e.g., 'is_active' => 'boolean:default(true)', eliminating the need for separate $attributes.

It now auto-detects the model via route model binding, so you can call $this->authorizeResource() without passing the model class.

It's a clearer, optimized alternative to updateOrInsert for atomically inserting or updating records based on unique keys.

New directives include @checked, @disabled, and @readonly for cleaner conditional attributes in form inputs.

It conditionally adds a where clause only if the provided value is filled (not empty), simplifying query building.

It auto-detects unique keys from database indexes, so you no longer need to manually specify them in the upsert call.

It allows efficient chunked loading of models in descending ID order, ideal for processing large datasets in reverse chronological order.