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

# Laravel 11에서 12로의 업그레이드 가이드

> Laravel 11에서 12로의 업그레이드 절차와 주요 변경점을 설명합니다

## 시작하며

Laravel 12는 2025년 2월에 릴리스되었습니다. 이 가이드에서는 Laravel 11.x에서 12.x로의 업그레이드 절차를 설명합니다.

<Info>
  업그레이드에 필요한 예상 시간은 **약 5분**입니다. 다만 파괴적 변경이 애플리케이션에 미치는 영향은 규모나 사용하고 있는 기능에 따라 다릅니다.
</Info>

### Laravel Shift를 사용한 자동 업그레이드

[Laravel Shift](https://laravelshift.com/)를 사용하여 업그레이드를 자동화할 수도 있습니다. Shift는 애플리케이션의 의존관계나 설정 파일을 자동으로 갱신해 줍니다.

***

## 영향도별 변경점

### 영향도: 높음

* 의존관계 갱신
* Laravel 인스톨러의 갱신

### 영향도: 중간

* Eloquent `HasUuids` 트레이트와 UUIDv7

### 영향도: 낮음

* Carbon 3
* Concurrency의 결과 인덱스 매핑
* 컨테이너의 클래스 의존 해결
* 이미지 유효성 검증의 SVG 제외
* 로컬 파일 시스템 디스크의 기본 루트 경로
* 멀티 스키마의 데이터베이스 인스펙션
* 중첩된 배열 요청의 병합

***

## 업그레이드 절차

### 의존관계 갱신

**영향도: 높음**

`composer.json`의 이하 의존관계를 갱신해 주세요.

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

갱신 후, 이하 명령으로 의존관계를 설치합니다.

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

***

### Laravel 인스톨러 갱신

**영향도: 높음**

Laravel 인스톨러 CLI를 사용하여 새 Laravel 애플리케이션을 만들 경우에는, Laravel 12.x 및 [새로운 스타터 킷](https://laravel.com/starter-kits)에 대응한 버전으로 갱신해 주세요.

`composer global require`로 설치한 경우:

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

`php.new`로 설치한 경우에는 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}
    # 관리자로 실행
    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>

[Laravel Herd](https://herd.laravel.com)의 번들 버전을 사용하고 있는 경우에는 Herd 자체를 최신 릴리스로 갱신해 주세요.

***

## 새 스타터 킷

Laravel 12에서는 기존의 Breeze나 Jetstream을 대신하는 새로운 스타터 킷이 도입되었습니다. `laravel new`를 실행하면 프론트엔드 스택을 대화식으로 선택할 수 있습니다.

이용 가능한 스타터 킷:

* **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
```

명령을 실행하면 스타터 킷의 선택이 촉구됩니다. 선택 후에는 의존관계를 설치하고 개발 서버를 기동하는 것만으로 됩니다.

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

<Info>
  기존 애플리케이션을 업그레이드하는 경우, 스타터 킷을 다시 도입할 필요는 없습니다. 신규 프로젝트용 변경입니다.
</Info>

***

## 파괴적 변경 (Breaking Changes)

### Eloquent

#### `HasUuids` 트레이트와 UUIDv7

**영향도: 중간**

`HasUuids` 트레이트가 UUID v7 (순서가 있는 UUID)를 반환하도록 되었습니다. 이전의 순서 있는 UUID v4의 동작을 유지하고 싶은 경우에는 `HasVersion4Uuids` 트레이트로 전환해 주세요.

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

이전부터 `HasVersion7Uuids` 트레이트를 사용하고 있었던 경우에는 `HasUuids` 트레이트로 변경해 주세요 (동일한 동작이 되었습니다).

***

### 유효성 검증

#### 이미지 유효성 검증의 SVG 제외

**영향도: 낮음**

`image` 유효성 검증 룰이 기본으로 SVG를 허가하지 않게 되었습니다. SVG를 허가하는 경우는 명시적으로 지정해 주세요.

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

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

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

***

### 스토리지

#### 로컬 파일 시스템 디스크의 기본 루트 경로

**영향도: 낮음**

`filesystems` 설정에서 `local` 디스크를 명시적으로 정의하지 않은 경우, 기본 루트 경로가 `storage/app`에서 `storage/app/private`로 변경되었습니다.

이전의 동작을 유지하려면, 설정 파일에서 `local` 디스크를 명시적으로 정의해 주세요.

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

***

### 데이터베이스

#### 멀티 스키마의 데이터베이스 인스펙션

**영향도: 낮음**

`Schema::getTables()`, `Schema::getViews()`, `Schema::getTypes()`가 기본으로 모든 스키마의 결과를 반환하도록 되었습니다. 특정 스키마만을 대상으로 하려면 `schema` 인자를 전달해 주세요.

```php theme={null}
// 모든 스키마의 테이블
$tables = Schema::getTables();

// 'main' 스키마의 테이블만
$tables = Schema::getTables(schema: 'main');
```

`Schema::getTableListing()`이 기본으로 스키마 수식된 테이블 이름을 반환하도록 되었습니다.

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

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

#### 데이터베이스 생성자 시그니처 변경

**영향도: 매우 낮음**

`Illuminate\Database\Schema\Blueprint`와 `Illuminate\Database\Grammar`의 생성자가 `Connection` 인스턴스를 첫 번째 인자로 요구하도록 되었습니다.

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

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

또한 이하의 API가 삭제 또는 비권장이 되었습니다.

| API                                              | 상태  |
| ------------------------------------------------ | --- |
| `Blueprint::getPrefix()`                         | 비권장 |
| `Connection::withTablePrefix()`                  | 삭제  |
| `Grammar::getTablePrefix()` / `setTablePrefix()` | 비권장 |
| `Grammar::setConnection()`                       | 삭제  |

테이블 프리픽스는 커넥션에서 직접 취득해 주세요.

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

***

### Concurrency

#### 결과 인덱스 매핑

**영향도: 낮음**

`Concurrency::run()`에 연관 배열을 전달한 경우, 결과가 각각의 키와 대응하여 반환되도록 되었습니다.

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

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

***

### 컨테이너

#### 클래스 의존 해결의 기본값

**영향도: 낮음**

DI 컨테이너가 클래스 인스턴스를 해결할 때 클래스 프로퍼티의 기본값을 존중하도록 되었습니다.

```php theme={null}
class Example
{
    public function __construct(public ?Carbon $date = null) {}
}

$example = resolve(Example::class);

// Laravel <= 11.x: Carbon 인스턴스 반환
// Laravel >= 12.x: null 반환
```

***

### 요청

#### 중첩된 배열 요청의 병합

**영향도: 낮음**

`$request->mergeIfMissing()`에서 점 표기법을 사용한 중첩된 배열 데이터를 병합할 수 있게 되었습니다. 이전에는 점 표기법의 키가 그대로 최상위 키로서 작성되고 있었습니다.

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

***

### 라우팅

#### 라우트의 우선순위

**영향도: 낮음**

같은 이름을 가진 여러 라우트가 있는 경우의 동작이, 캐시 유/무에서 통일되었습니다. 캐시 없는 라우팅에서도, 마지막이 아니라 최초로 등록된 라우트가 우선되도록 되었습니다.

***

### 인증

#### `DatabaseTokenRepository` 생성자의 변경

**영향도: 매우 낮음**

`Illuminate\Auth\Passwords\DatabaseTokenRepository`의 생성자가 `$expires` 파라미터를 분 단위가 아니라 초 단위로 받도록 되었습니다.

***

### Carbon 3

**영향도: 낮음**

Carbon 2.x의 지원이 삭제되었습니다. Laravel 12의 애플리케이션은 모두 [Carbon 3.x](https://carbon.nesbot.com/guide/getting-started/migration.html)가 필요합니다.

***

## 정리

Laravel 12는 비교적 부드럽게 업그레이드할 수 있는 버전입니다. 주요 주의점을 정리합니다.

| 변경점                      | 영향도 | 대응                             |
| ------------------------ | --- | ------------------------------ |
| `composer.json`의 의존관계 갱신 | 높음  | `laravel/framework ^12.0`으로 변경 |
| Laravel 인스톨러의 갱신         | 높음  | `composer global update`       |
| `HasUuids` → UUIDv7      | 중간  | 필요하면 `HasVersion4Uuids`로 전환    |
| `image` 유효성 검증의 SVG 제외   | 낮음  | SVG를 허가하는 경우는 `allow_svg` 추가   |
| 로컬 디스크의 기본 루트 변경         | 낮음  | 설정 파일에서 명시적으로 지정               |
| Carbon 3 필수              | 낮음  | API 호환성 확인                     |

***

## 참고 자료

* [공식 업그레이드 가이드 (영어)](https://laravel.com/docs/12.x/upgrade)
* [laravel/laravel 리포지토리의 차분 (11.x → 12.x)](https://github.com/laravel/laravel/compare/11.x...12.x)
* [새로운 스타터 킷](https://laravel.com/starter-kits)
* [Laravel Shift](https://laravelshift.com) — 업그레이드를 자동화하는 커뮤니티 서비스
* [Carbon 3 마이그레이션 가이드](https://carbon.nesbot.com/guide/getting-started/migration.html)


## Related topics

- [Laravel 12에서 13으로의 업그레이드 가이드](/ko/blog/upgrade-12-to-13.md)
- [Laravel 10에서 11로의 업그레이드](/ko/blog/upgrade-10-to-11.md)
- [Laravel 8에서 9로의 업그레이드](/ko/blog/upgrade-8-to-9.md)
- [Laravel 9에서 10으로의 업그레이드](/ko/blog/upgrade-9-to-10.md)
