> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrade guide: Laravel 11 to 12

> Upgrade steps and major changes when moving from Laravel 11 to 12.

## Introduction

Laravel 12 was released in February 2025. This guide walks through upgrading from Laravel 11.x to 12.x.

<Info>
  Estimated time to upgrade is **about 5 minutes**. Actual impact from breaking changes depends on your app's size and features you use.
</Info>

### Automated upgrades with Laravel Shift

You can automate the upgrade using [Laravel Shift](https://laravelshift.com/). Shift updates dependencies and configuration files automatically.

***

## Changes by impact level

### Impact: high

* Dependency updates
* Laravel installer update

### Impact: medium

* Eloquent `HasUuids` trait and UUIDv7

### Impact: low

* Carbon 3
* Concurrency result index mapping
* Container class dependency resolution
* SVG exclusion from image validation
* Default root path for the local filesystem disk
* Multi-schema database inspection
* Merging nested array requests

***

## Upgrade steps

### Update dependencies

**Impact: high**

Update the following dependencies in `composer.json`.

```json theme={null}
{
  "require": {
    "laravel/framework": "^12.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^11.0",
    "pestphp/pest": "^3.0"
  }
}
```

Then install dependencies:

```shell theme={null}
composer update
```

***

### Update the Laravel installer

**Impact: high**

If you use the Laravel installer CLI to create new Laravel apps, update it to the version that supports Laravel 12.x and the [new starter kits](https://laravel.com/starter-kits).

If installed via `composer global require`:

```shell theme={null}
composer global update laravel/installer
```

If installed via `php.new`, run the reinstall command for your OS.

<Tabs>
  <Tab title="macOS">
    ```shell theme={null}
    /bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)"
    ```
  </Tab>

  <Tab title="Windows PowerShell">
    ```shell theme={null}
    # Run as administrator
    Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://php.new/install/windows/8.4'))
    ```
  </Tab>

  <Tab title="Linux">
    ```shell theme={null}
    /bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)"
    ```
  </Tab>
</Tabs>

If you use the [Laravel Herd](https://herd.laravel.com) bundled version, update Herd itself to its latest release.

***

## New starter kits

Laravel 12 introduces new starter kits to replace the previous Breeze and Jetstream. Running `laravel new` lets you interactively pick 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

```shell theme={null}
laravel new my-app
```

Running the command prompts you to choose a starter kit. After choosing, install dependencies and start the dev server.

```shell theme={null}
cd my-app
npm install && npm run build
composer run dev
```

<Info>
  When upgrading existing apps, you don't need to reinstall a starter kit. It's a change for new projects.
</Info>

***

## Breaking changes

### Eloquent

#### `HasUuids` trait and UUIDv7

**Impact: medium**

The `HasUuids` trait now returns UUID v7 (ordered UUIDs). To keep the previous ordered UUID v4 behavior, switch to the `HasVersion4Uuids` trait.

```php theme={null}
use Illuminate\Database\Eloquent\Concerns\HasUuids; // [tl! remove]
use Illuminate\Database\Eloquent\Concerns\HasVersion4Uuids as HasUuids; // [tl! add]
```

If you previously used the `HasVersion7Uuids` trait, switch to `HasUuids` (which now has the same behavior).

***

### Validation

#### SVG exclusion from image validation

**Impact: low**

The `image` validation rule no longer allows SVG by default. To allow SVG, specify it explicitly.

```php theme={null}
use Illuminate\Validation\Rules\File;

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

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

***

### Storage

#### Default root path for the local filesystem disk

**Impact: low**

If the `local` disk isn't explicitly defined in the `filesystems` configuration, its default root path has changed from `storage/app` to `storage/app/private`.

To keep the previous behavior, define the `local` disk explicitly in the configuration file.

```php theme={null}
// config/filesystems.php
'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
],
```

***

### Database

#### Multi-schema database inspection

**Impact: low**

`Schema::getTables()`, `Schema::getViews()`, and `Schema::getTypes()` now return results from all schemas by default. To target only a specific schema, pass the `schema` argument.

```php theme={null}
// Tables from all schemas
$tables = Schema::getTables();

// Tables from only the 'main' schema
$tables = Schema::getTables(schema: 'main');
```

`Schema::getTableListing()` now returns schema-qualified table names by default.

```php theme={null}
$tables = Schema::getTableListing();
// ['main.migrations', 'main.users', 'blog.posts']

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

#### Database constructor signature change

**Impact: very low**

`Illuminate\Database\Schema\Blueprint` and `Illuminate\Database\Grammar` constructors now require a `Connection` instance as their first argument.

```php theme={null}
// Laravel <= 11.x
$grammar = new MySqlGrammar;
$grammar->setConnection($connection);

// Laravel >= 12.x
$grammar = new MySqlGrammar($connection);
```

The following APIs are also deprecated or removed.

| API                                              | Status     |
| ------------------------------------------------ | ---------- |
| `Blueprint::getPrefix()`                         | Deprecated |
| `Connection::withTablePrefix()`                  | Removed    |
| `Grammar::getTablePrefix()` / `setTablePrefix()` | Deprecated |
| `Grammar::setConnection()`                       | Removed    |

Get the table prefix directly from the connection.

```php theme={null}
$prefix = $connection->getTablePrefix();
```

***

### Concurrency

#### Result index mapping

**Impact: low**

When you pass an associative array to `Concurrency::run()`, results are now returned associated with their keys.

```php theme={null}
$result = Concurrency::run([
    'task-1' => fn () => 1 + 1,
    'task-2' => fn () => 2 + 2,
]);

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

***

### Container

#### Default values in class dependency resolution

**Impact: low**

The DI container now respects default class property values when resolving class instances.

```php theme={null}
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
```

***

### Requests

#### Merging nested array requests

**Impact: low**

`$request->mergeIfMissing()` can now merge nested array data using dot notation. Previously, dot-notation keys were created as top-level keys as-is.

```php theme={null}
$request->mergeIfMissing([
    'user.last_name' => 'Otwell',
]);
```

***

### Routing

#### Route priority

**Impact: low**

The behavior when multiple routes have the same name is now consistent between cached and uncached routing. Even without caching, the first-registered route now wins instead of the last.

***

### Authentication

#### `DatabaseTokenRepository` constructor change

**Impact: very low**

The `Illuminate\Auth\Passwords\DatabaseTokenRepository` constructor's `$expires` parameter now takes seconds rather than minutes.

***

### Carbon 3

**Impact: low**

Carbon 2.x support has been dropped. All Laravel 12 apps require [Carbon 3.x](https://carbon.nesbot.com/guide/getting-started/migration.html).

***

## Summary

Laravel 12 is a comparatively smooth upgrade. Here are the main things to watch out for.

| Change                                | Impact | Action                                 |
| ------------------------------------- | ------ | -------------------------------------- |
| Update `composer.json` dependencies   | High   | Set `laravel/framework ^12.0`          |
| Update the Laravel installer          | High   | `composer global update`               |
| `HasUuids` → UUIDv7                   | Medium | Switch to `HasVersion4Uuids` if needed |
| SVG exclusion from `image` validation | Low    | Add `allow_svg` to allow SVG           |
| Default root of local disk changed    | Low    | Specify explicitly in config           |
| Carbon 3 required                     | Low    | Verify API compatibility               |

***

## References

* [Official upgrade guide (English)](https://laravel.com/docs/12.x/upgrade)
* [laravel/laravel diff (11.x → 12.x)](https://github.com/laravel/laravel/compare/11.x...12.x)
* [New starter kits](https://laravel.com/starter-kits)
* [Laravel Shift](https://laravelshift.com) — community service to automate upgrades
* [Carbon 3 migration guide](https://carbon.nesbot.com/guide/getting-started/migration.html)


## Related topics

- [Upgrade guide: Laravel 12 to 13](/en/blog/upgrade-12-to-13.md)
- [Upgrading from Laravel 10 to 11](/en/blog/upgrade-10-to-11.md)
- [Laravel 13 new features overview](/en/blog/laravel-13-new-features.md)
- [Package CHANGELOG and Release Management](/en/advanced/package-changelog.md)
- [Migration Guide: Old Structure to Slim Application Skeleton](/en/advanced/app-structure-migration.md)
