Skip to content

Laravel 12 Is a Maintenance Release, and I’m Oddly Relieved

Laravel 12 Is a Maintenance Release, and I’m Oddly Relieved

Confession: I opened the Laravel 12 upgrade guide expecting to lose a weekend, and instead I was done before my coffee went cold. I ran the composer bump, the app booted, my tests stayed green, and I sat there feeling faintly cheated. Where was the drama? Where were the deprecations that usually eat half a Saturday?

There weren’t any. Laravel 12 is a maintenance release, and after a year of running it in production I’ve decided that’s the best thing about it. The listicles want to sell you ten “game-changing” features. The real story is quieter and more useful, so let me walk you through what actually changed and what to do about it.

What Laravel 12 actually is

Laravel 12 shipped in February 2025, and the framework’s own release notes are refreshingly blunt about it: it’s a maintenance release that bumps upstream dependencies and keeps the internals current. Most apps upgrade without touching a single line of application code. That was true for me across three projects, including one crusty API I’d been dreading.

If you’ve been on Laravel for a while, you know this isn’t how it always felt. The jump to 8, the switch to the streamlined skeleton in 11, those took planning. Laravel 12 is the opposite. The upgrade is close to boring, and I mean that as praise. A framework that respects your time on the boring releases is a framework you can trust on the exciting ones.

Here’s the whole upgrade for a typical app:

# bump the framework constraint
composer require laravel/framework:^12.0 --update-with-dependencies

# run your suite and actually read the output
php artisan test

That’s it for most people. No config rewrite, no mass find-and-replace. If something does break, it’s usually a third-party package that hasn’t tagged 12 support yet, not Laravel itself.

There’s a reason it goes this smoothly, and it’s worth understanding rather than just enjoying. Laravel moved to a yearly release cadence a while back, and the whole point of that rhythm is to spread breaking changes thin. Instead of one terrifying major every couple of years, you get small, digestible bumps. Laravel 12 is what that discipline looks like when it’s working. The maintainers spent their effort on keeping dependencies current and the skeleton clean rather than inventing churn so the release notes look busy. I’ve come to see a short changelog as a feature, not a disappointment.

The one upgrade gotcha worth checking

If there’s a single thing that’ll bite you, it isn’t in Laravel’s code, it’s in your composer.json. Laravel 12 requires PHP 8.2 or newer, so if you’re clinging to an older runtime on some legacy box, sort that out first. Bump your PHP version, run your suite, and only then bump the framework. Doing both at once turns a clean five-minute upgrade into a confusing hunt for which change caused which failure.

The second thing to check is your package graph. Run composer outdated before you upgrade and skim it for anything that hasn’t shipped a Laravel 12 compatible tag. Most popular packages moved quickly, but the long tail of smaller, single-maintainer packages is where the delays live. If a critical dependency is stuck, you’re better off waiting a week than forking it in a panic.

# see what might block you before you commit
composer outdated --direct

# then upgrade PHP first, framework second, one at a time

None of this is hard. It’s just the difference between an upgrade that feels calm and one that feels like debugging in the dark.

The starter kits are the real headline

The thing worth caring about isn’t in the core, it’s in how new apps get scaffolded. Laravel 12 introduced new starter kits for React, Vue, Svelte, and Livewire, and they quietly retired the old approach. Laravel Breeze and Jetstream are no longer getting updates. If you reach for them out of muscle memory, stop.

The React, Vue, and Svelte kits ship with Inertia 2, TypeScript, and a shadcn-style component setup. The Livewire kit uses Flux UI and Volt. This matters because the old Breeze scaffolding always felt like a starting point you immediately had to rip apart. The new kits feel closer to something you’d actually keep.

Spinning one up looks like this:

# old muscle memory (don't do this anymore)
composer require laravel/breeze --dev
php artisan breeze:install react

# the Laravel 12 way
laravel new my-app
# then pick a starter kit and stack from the prompts:
#   React + Inertia 2 + TypeScript + shadcn
#   Vue + Inertia 2 + TypeScript
#   Livewire + Flux UI + Volt

I was skeptical of the shadcn direction at first. Component libraries you don’t control tend to become the thing you fight in month three. But because the components are copied into your project rather than pulled from a package, you own them outright. When I needed a weird variant of a dialog, I just edited the file. No wrapper, no override soup.

The Inertia 2 choice is the other quiet upgrade. If you’ve never used Inertia, it lets you build a single-page-app feel with React or Vue on the front while keeping your routing and controllers in plain Laravel on the back. You skip building and versioning a separate API for your own frontend, which for a small team is a real chunk of work you get to not do. I’ve shipped both a decoupled React-plus-API setup and an Inertia one for comparable projects, and the Inertia version had noticeably less glue code to maintain. That’s the kind of thing that doesn’t show up in a feature list but shows up in your Friday afternoons.

The Livewire kit is the pick if you’d rather stay in PHP and treat JavaScript as a garnish. Flux UI gives it a polished component set, and Volt lets you colocate the logic so a component isn’t split across two files for no reason. For internal tools and admin panels, where you want to move fast and nobody’s judging your bundle size, it’s genuinely lovely.

WorkOS AuthKit, and when to skip it

Each starter kit has a WorkOS variant, and this is where I’ll push back on the hype a little. The WorkOS AuthKit option gives you social login, passkeys, and SSO out of the box, which is genuinely handy if you’re building something that sells to companies with an IT department. SSO is table stakes for B2B, and rolling it yourself is miserable.

But for a side project or a consumer app, pulling in a hosted auth provider on day one is a commitment you don’t need yet. The plain starter kit gives you session auth that works and costs nothing. I’ve shipped things both ways, and I regret reaching for the heavier option more often than the lighter one. Start with what’s free, add the identity provider when a customer asks for SAML.

// the WorkOS variant wires this up for you, but conceptually:
Route::get('/login', function () {
    return Socialite::driver('workos')->redirect();
});

// vs. the plain kit, which just uses Laravel's own session guard
// and a login controller you can read top to bottom

The point isn’t that one is better. It’s that the framework now hands you the choice at scaffold time instead of making you glue it together later.

What to actually do this week

If you’re already on Laravel 11, budget an hour, run the composer bump, and read your test output carefully. Not skim it, read it. The upgrade is easy precisely because the failure signal is quiet, and a quiet signal is easy to miss.

If you’re starting something new, use a Laravel 12 starter kit instead of Breeze, and pick the stack you already know rather than the trendiest one. I went deep on the Livewire-plus-Volt combo for an internal tool and wrote up the tradeoffs against a JS-heavy stack in my take on Symfony versus Laravel, which covers when I reach for the full-page-reload world versus the SPA one.

And if you maintain a package, tag your 12 compatibility. Half the “Laravel 12 broke my app” complaints I’ve seen trace back to a dependency that never updated, not the framework. Laravel News keeps a running summary of what landed across the 12.x point releases if you want to track the smaller stuff.

I build and maintain PHP backends like this for a living, and you can see some of that work on my portfolio. The lesson Laravel 12 reinforced for me is unglamorous but real: a release that gives you nothing to do is a release doing its job. Save your weekends for the features you actually ship.