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.

Table Of Content
1 Laravel 12 Requirements
Before starting the Laravel 12 install process, ensure you meet the following Laravel 12 requirements:
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?
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)',
];
}
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!)
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)
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!)
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);
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!)
Efficiently load large datasets in reverse order.
User::lazyByIdDesc()->each(function ($user) {
// Process each user
});
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
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.
