Skip to main content

Documentation Index

Fetch the complete documentation index at: https://kawax.biz/llms.txt

Use this file to discover all available pages before exploring further.

Introduction

Laravel 12 was released in February 2025. This guide covers everything you need to upgrade a Laravel 11.x application to 12.x.
Estimated upgrade time: about 5 minutes. The actual impact depends on the size of your application and which features you use.

Automated upgrade with Laravel Shift

You can automate much of the upgrade process using Laravel Shift. Shift automatically updates your dependencies and configuration files.

Changes by impact level

High impact

  • Updating dependencies
  • Updating the Laravel installer

Medium impact

  • Eloquent HasUuids trait and UUIDv7

Low impact

  • Carbon 3
  • Concurrency result index mapping
  • Container class dependency resolution
  • Image validation SVG exclusion
  • Local filesystem disk default root path
  • Multi-schema database inspection
  • Nested array request merging

Upgrade steps

Updating dependencies

High impact Update the following entries in your composer.json:
{
  "require": {
    "laravel/framework": "^12.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^11.0",
    "pestphp/pest": "^3.0"
  }
}
Then install the updated dependencies:
composer update

Updating the Laravel installer

High impact If you use the Laravel installer CLI to create new applications, update it to the version that supports Laravel 12.x and the new starter kits. If you installed it with composer global require:
composer global update laravel/installer
If you installed it with php.new, re-run the install command for your OS:
/bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)"
If you use the version bundled with Laravel Herd, update Herd itself to the latest release.

New starter kits

Laravel 12 introduces a new set of starter kits that replace the older Breeze and Jetstream packages. Running laravel new now interactively prompts you to select a frontend stack. Available starter kits:
  • React — Inertia 2, React 19, TypeScript, Tailwind 4, shadcn/ui
  • Vue — Inertia 2, Vue Composition API, TypeScript, Tailwind 4, shadcn-vue
  • Svelte — Inertia 2, Svelte 5, TypeScript, Tailwind 4, shadcn-svelte
  • Livewire — Livewire, Tailwind 4, Flux UI
laravel new my-app
After selecting a kit, install dependencies and start the dev server:
cd my-app
npm install && npm run build
composer run dev
If you’re upgrading an existing application, you don’t need to adopt a starter kit. They are intended for new projects.

Breaking changes

Eloquent

HasUuids trait and UUIDv7

Medium impact The HasUuids trait now generates UUID v7 (time-ordered UUIDs) instead of UUID v4. If you need to keep the previous UUID v4 behavior, switch to the HasVersion4Uuids trait.
use Illuminate\Database\Eloquent\Concerns\HasUuids; // [tl! remove]
use Illuminate\Database\Eloquent\Concerns\HasVersion4Uuids as HasUuids; // [tl! add]
If you were already using HasVersion7Uuids, you can switch to HasUuids — the behavior is now identical.

Validation

Image validation excludes SVG by default

Low impact The image validation rule no longer accepts SVG files by default. To allow SVGs explicitly:
use Illuminate\Validation\Rules\File;

'photo' => 'required|image:allow_svg'

// or
'photo' => ['required', File::image(allowSvg: true)],

Storage

Local filesystem disk default root path

Low impact If you have not explicitly defined a local disk in your filesystems configuration, the default root path has changed from storage/app to storage/app/private. To keep the previous behavior, define the local disk explicitly:
// config/filesystems.php
'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
],

Database

Multi-schema database inspection

Low impact Schema::getTables(), Schema::getViews(), and Schema::getTypes() now return results from all schemas by default. To target a specific schema, pass the schema argument:
// All schemas
$tables = Schema::getTables();

// Only the 'main' schema
$tables = Schema::getTables(schema: 'main');
Schema::getTableListing() now returns schema-qualified table names by default:
$tables = Schema::getTableListing();
// ['main.migrations', 'main.users', 'blog.posts']

$tables = Schema::getTableListing(schema: 'main', schemaQualified: false);
// ['migrations', 'users']

Database constructor signature changes

Very low impact Illuminate\Database\Schema\Blueprint and Illuminate\Database\Grammar now require a Connection instance as their first constructor argument.
// Laravel <= 11.x
$grammar = new MySqlGrammar;
$grammar->setConnection($connection);

// Laravel >= 12.x
$grammar = new MySqlGrammar($connection);
The following APIs have been removed or deprecated:
APIStatus
Blueprint::getPrefix()Deprecated
Connection::withTablePrefix()Removed
Grammar::getTablePrefix() / setTablePrefix()Deprecated
Grammar::setConnection()Removed
Retrieve the table prefix directly from the connection:
$prefix = $connection->getTablePrefix();

Concurrency

Result index mapping

Low impact When you pass an associative array to Concurrency::run(), results are now keyed by the same keys:
$result = Concurrency::run([
    'task-1' => fn () => 1 + 1,
    'task-2' => fn () => 2 + 2,
]);

// ['task-1' => 2, 'task-2' => 4]

Container

Class dependency resolution default values

Low impact The DI container now respects default values when resolving class instances with nullable class properties.
class Example
{
    public function __construct(public ?Carbon $date = null) {}
}

$example = resolve(Example::class);

// Laravel <= 11.x: returns a Carbon instance
// Laravel >= 12.x: returns null

Request

Nested array request merging

Low impact $request->mergeIfMissing() now correctly merges nested array data using dot notation. Previously, dot-notation keys were added as literal top-level keys.
$request->mergeIfMissing([
    'user.last_name' => 'Otwell',
]);

Routing

Route priority

Low impact The behavior for multiple routes with the same name is now consistent whether or not the route cache is active. Without cache, the first registered route now wins — not the last.

Authentication

DatabaseTokenRepository constructor change

Very low impact The $expires parameter in Illuminate\Auth\Passwords\DatabaseTokenRepository now expects seconds instead of minutes.

Carbon 3

Low impact Support for Carbon 2.x has been dropped. Laravel 12 applications require Carbon 3.x.

Summary

Laravel 12 is a relatively smooth upgrade. Here’s a quick reference for the key changes:
ChangeImpactAction required
Update composer.json dependenciesHighChange to laravel/framework ^12.0
Update the Laravel installerHighRun composer global update
HasUuids now generates UUIDv7MediumSwitch to HasVersion4Uuids if needed
image validation excludes SVGLowAdd allow_svg if you need SVG support
Local disk default root path changedLowDefine the local disk explicitly
Carbon 3 requiredLowReview API compatibility

References

Last modified on April 19, 2026