> ## 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 12에서 13으로의 업그레이드 가이드

> Laravel 12에서 Laravel 13으로의 업그레이드 절차, 파괴적 변경, 비권장 기능, 및 새 기능의 하이라이트를 설명합니다.

## 시작하며

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

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

### AI를 사용한 업그레이드

[Laravel Boost](https://github.com/laravel/boost)를 사용하여 업그레이드를 자동화할 수도 있습니다. Boost는 퍼스트파티 MCP 서버로, AI 어시스턴트에 단계적인 업그레이드 프롬프트를 제공합니다. Laravel 12 애플리케이션에 설치한 후, Claude Code, Cursor, OpenCode, Gemini, VS Code에서 `/upgrade-laravel-v13` 슬래시 명령을 사용하여 Laravel 13으로의 업그레이드를 시작할 수 있습니다. 이 명령에는 `laravel/boost ^2.0`이 필요합니다.

슬래시 명령을 사용할 수 없는 AI 도구에서도 프롬프트 파일을 직접 참조함으로써 같은 업그레이드 절차를 실행할 수 있습니다. 아래의 프롬프트를 그대로 AI에 붙여 넣어 주세요.

```text 프롬프트 theme={null}
Laravel Boost가 제공하고 있는 프롬프트를 로드하여 Laravel 12에서 13으로의 업그레이드 작업을 수행해 주세요.
https://raw.githubusercontent.com/laravel/boost/refs/heads/main/src/Mcp/Prompts/UpgradeLaravelv13/upgrade-laravel-v13.blade.php

- `laravel/laravel` 스켈레톤의 변경점을 반영시킨다. master가 아니라 13.x 브랜치를 확인한다.
- `database/migrations/*_create_cache_table.php`는 그대로 변경이 아니라 새 마이그레이션을 작성.
- `config/session.php`의 `serialization`은 `php`로 설정. `'serialization' => 'php'`
- Laravel 13에서 가장 앱에 오류를 발생시키는 변경은 캐시의 동작 변경이므로 프로젝트 내 캐시 사용 부분을 검색하여 허가해도 문제 없을 것 같으면 config/cache.php의 `serializable_classes`에서 허가하도록 갱신.

'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
    Illuminate\Support\Collection::class,
    Illuminate\Database\Eloquent\Collection::class,
],
```

***

## 영향도별 변경점

### 영향도: 높음

* 의존관계 갱신
* Laravel 인스톨러 갱신
* 요청 위조 방지 (CSRF)

### 영향도: 중간

* 캐시 `serializable_classes` 설정
* 세션 `serialization` 설정

### 영향도: 낮음

* 캐시 프리픽스와 세션 쿠키 이름
* 컬렉션 모델 시리얼라이제이션
* `Container::call`과 Nullable 클래스 기본값
* 도메인 라우트 등록의 우선순위
* `JobAttempted` 이벤트의 예외 페이로드
* Manager `extend` 콜백의 바인딩
* MySQL `DELETE` 쿼리 (JOIN / ORDER BY / LIMIT)
* 페이지네이션 Bootstrap 뷰 이름
* 폴리모픽 피벗 테이블 이름의 생성
* `QueueBusy` 이벤트의 프로퍼티 이름 변경
* `Str` 팩토리의 테스트 간 리셋

***

## 업그레이드 절차

### 의존관계 갱신

**영향도: 높음**

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

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

Laravel Boost를 사용하고 있는 경우에는 함께 갱신합니다.

```json theme={null}
{
  "require": {
    "laravel/boost": "^2.0"
  }
}
```

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

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

***

### Laravel 인스톨러 갱신

**영향도: 높음**

Laravel 인스톨러 CLI를 사용하여 새 Laravel 애플리케이션을 만드는 경우, Laravel 13.x 대응 버전으로 갱신해 주세요.

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

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

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

***

## 파괴적 변경 (Breaking Changes)

### 보안

#### 요청 위조 방지

**영향도: 높음**

Laravel의 CSRF 미들웨어가 `VerifyCsrfToken`에서 `PreventRequestForgery`로 리네임되었습니다. 또한 `Sec-Fetch-Site` 헤더를 이용한 요청 발신처의 검증이 추가되었습니다.

`VerifyCsrfToken`과 `ValidateCsrfToken`은 비권장 별칭으로 남아 있지만, 직접 참조하고 있는 부분은 모두 `PreventRequestForgery`로 갱신할 필요가 있습니다. 특히 테스트나 라우트 정의에서 미들웨어를 제외하고 있는 경우에는 주의가 필요합니다.

```php theme={null}
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;

// Laravel <= 12.x
->withoutMiddleware([VerifyCsrfToken::class]);

// Laravel >= 13.x
->withoutMiddleware([PreventRequestForgery::class]);
```

미들웨어 설정 API에서도 `preventRequestForgery(...)`가 사용 가능해졌습니다.

***

### 캐시

#### 캐시 프리픽스와 세션 쿠키 이름

**영향도: 낮음**

Laravel의 기본 캐시 및 Redis 키 프리픽스가 하이픈 구분의 서픽스를 사용하도록 되었습니다. 또한 기본 세션 쿠키 이름이 `Str::snake(...)`를 사용하도록 되었습니다.

많은 애플리케이션에서는 설정 파일에서 명시적으로 값을 설정하고 있으므로, 이 변경의 영향을 받지 않습니다. 프레임워크의 폴백 설정에 의존하고 있는 애플리케이션만 영향을 받습니다.

```php theme={null}
// Laravel <= 12.x
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_cache_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_database_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_session';

// Laravel >= 13.x
Str::slug((string) env('APP_NAME', 'laravel')).'-cache-';
Str::slug((string) env('APP_NAME', 'laravel')).'-database-';
Str::snake((string) env('APP_NAME', 'laravel')).'_session';
```

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

```ini theme={null}
CACHE_PREFIX=myapp_cache_
REDIS_PREFIX=myapp_database_
SESSION_COOKIE=myapp_session
```

#### 캐시 `serializable_classes` 설정

**영향도: 중간**

기본 `cache` 설정에 `serializable_classes` 옵션이 추가되었으며, 기본은 `false`가 되었습니다. 이로 인해 `APP_KEY`가 유출된 경우의 PHP 디시리얼라이제이션 가젯 체인 공격을 방지합니다.

애플리케이션이 의도적으로 캐시에 PHP 오브젝트를 저장하고 있는 경우, 디시리얼라이즈를 허가할 클래스를 명시적으로 리스트업할 필요가 있습니다.

```php theme={null}
// config/cache.php
'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
],
```

임의의 캐시 오브젝트를 디시리얼라이즈하고 있었던 경우에는, 명시적인 클래스 허가 리스트 또는 비오브젝트의 캐시 페이로드(배열 등)로 이관해야 합니다.

#### 세션 `serialization` 설정

**영향도: 중간**

Laravel 13의 스켈레톤(`laravel/laravel`)의 `config/session.php`에 `'serialization' => 'json'`이 추가되어 있습니다. 다만, 프레임워크 내부의 기본은 `php` 그대로입니다.

<Warning>
  AI 도구를 사용하여 스켈레톤의 변경을 그대로 적용한 경우, `config/session.php`에 `'serialization' => 'json'`이 추가되는 경우가 있습니다. 이 변경은 세션의 시리얼라이제이션 방식을 전환하므로, 세션에 PHP 오브젝트를 저장하고 있는 애플리케이션에서 오류가 발생할 가능성이 있습니다.
</Warning>

공식 업그레이드 가이드에는 이 설정의 변경이 기재되어 있지 않습니다. 이것은 **변경하지 않아도 된다**는 의도로 생각됩니다. Laravel에서는 하나 이전 버전에서의 업그레이드에서는 영향이 없으므로 업그레이드 가이드에 기재되지 않는 변경이 때때로 있습니다. 몇 년 후에 업그레이드하려고 했을 때 정보가 없어 곤란해지므로 비공식적인 기록이 중요합니다.

Laravel 12까지와 같은 동작을 유지하려면, `'serialization' => 'php'`를 명시적으로 설정해 주세요.

```php theme={null}
// config/session.php
'serialization' => 'php',
```

JSON 시리얼라이제이션을 활성화하는 경우에는, 세션에 PHP 오브젝트를 저장하고 있지 않은 것을 사전에 확인해 주세요.

***

### 컨테이너

#### `Container::call`과 Nullable 클래스 기본값

**영향도: 낮음**

`Container::call`이, 바인딩이 존재하지 않는 경우에 nullable 클래스 파라미터의 기본값을 존중하도록 되었습니다 (Laravel 12에서 생성자 인젝션에 도입된 동작과 일치합니다).

```php theme={null}
$container->call(function (?Carbon $date = null) {
    return $date;
});

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

***

### 데이터베이스

#### MySQL `DELETE` 쿼리

**영향도: 낮음**

Laravel이 MySQL 문법에서 `ORDER BY`와 `LIMIT`을 포함하는 완전한 `DELETE ... JOIN` 쿼리를 컴파일하도록 되었습니다.

이전 버전에서는 JOIN을 동반하는 DELETE에서 `ORDER BY` / `LIMIT` 절이 무시되는 경우가 있었습니다. Laravel 13에서는 이 절들이 생성되는 SQL에 포함됩니다. 그 결과, 이 구문을 지원하지 않는 일부 데이터베이스 엔진에서 `QueryException`이 발생할 가능성이 있습니다.

***

### Eloquent

#### 폴리모픽 피벗 테이블 이름의 생성

**영향도: 낮음**

커스텀 피벗 모델 클래스를 사용하는 폴리모픽 피벗 모델의 테이블 이름이 추측될 때, Laravel이 복수형 이름을 생성하도록 되었습니다.

이전의 단수형 추측 이름에 의존하고 있었던 경우에는 피벗 모델에서 테이블 이름을 명시적으로 정의해 주세요.

```php theme={null}
class RoleUser extends MorphPivot
{
    protected $table = 'role_user'; // 명시적으로 지정
}
```

#### 컬렉션 모델 시리얼라이제이션

**영향도: 낮음**

Eloquent 모델 컬렉션이 시리얼라이즈 및 리스토어(큐 투입된 잡 등)될 때, Eager 로드된 릴레이션이 모델을 위해 복원되도록 되었습니다.

디시리얼라이제이션 후에 릴레이션이 존재하지 않는 것에 의존하고 있었던 코드가 있는 경우에는 수정이 필요합니다.

***

### 큐

#### `JobAttempted` 이벤트의 예외 페이로드

**영향도: 낮음**

`Illuminate\Queue\Events\JobAttempted` 이벤트가 이전의 boolean인 `$exceptionOccurred` 프로퍼티 대신에, 예외 오브젝트(또는 `null`)를 `$exception`으로 공개하도록 되었습니다.

```php theme={null}
// Laravel <= 12.x
if ($event->exceptionOccurred) {
    // 예외가 발생했다
}

// Laravel >= 13.x
if ($event->exception !== null) {
    // 예외가 발생했다
    $exception = $event->exception;
}
```

#### `QueueBusy` 이벤트의 프로퍼티 이름 변경

**영향도: 낮음**

`Illuminate\Queue\Events\QueueBusy` 이벤트의 프로퍼티 `$connection`이, 다른 큐 이벤트와의 일관성을 위해 `$connectionName`으로 리네임되었습니다.

```php theme={null}
// Laravel <= 12.x
$event->connection;

// Laravel >= 13.x
$event->connectionName;
```

***

### 라우팅

#### 도메인 라우트 등록의 우선순위

**영향도: 낮음**

명시적인 도메인을 가지는 라우트가 라우트 매칭에서 비도메인 라우트보다 우선되도록 되었습니다.

이로 인해 캐치올 서브도메인 라우트가, 비도메인 라우트가 먼저 등록되어 있는 경우에도 일관되게 동작하도록 됩니다.

***

### 서포트

#### Manager `extend` 콜백의 바인딩

**영향도: 낮음**

Manager의 `extend` 메서드로 등록된 커스텀 드라이버의 클로저가, 매니저 인스턴스에 바인딩되도록 되었습니다.

이전에는 이 콜백들 내에서 별도의 오브젝트(서비스 프로바이더 인스턴스 등)가 `$this`로서 참조되고 있었던 경우, `use (...)`로 값을 클로저 캡처에 이동시켜야 합니다.

```php theme={null}
// Laravel <= 12.x
Manager::extend('custom', function ($app) {
    return $this->createCustomDriver($app); // $this는 서비스 프로바이더
});

// Laravel >= 13.x
$provider = $this;
Manager::extend('custom', function ($app) use ($provider) {
    return $provider->createCustomDriver($app);
});
```

#### `Str` 팩토리의 테스트 간 리셋

**영향도: 낮음**

Laravel이 테스트의 티어다운 시에 커스텀 `Str` 팩토리를 리셋하도록 되었습니다.

커스텀 UUID / ULID / 랜덤 문자열 팩토리가 테스트 메서드 간에 지속되는 것에 의존하고 있었던 경우에는, 관련된 각 테스트 또는 셋업 훅에서 설정하도록 해 주세요.

***

### 뷰

#### 페이지네이션 Bootstrap 뷰 이름

**영향도: 낮음**

Bootstrap 3 기본의 내부 페이지네이션 뷰 이름이 명시적으로 되었습니다.

```php theme={null}
// Laravel <= 12.x
pagination::default
pagination::simple-default

// Laravel >= 13.x
pagination::bootstrap-3
pagination::simple-bootstrap-3
```

오래된 페이지네이션 뷰 이름을 직접 참조하고 있는 경우에는 갱신해 주세요.

***

## 비권장이 된 기능

| 기능                                 | 대체 수단                        |
| ---------------------------------- | ---------------------------- |
| `VerifyCsrfToken` 미들웨어             | `PreventRequestForgery`      |
| `ValidateCsrfToken` 미들웨어           | `PreventRequestForgery`      |
| `JobAttempted::$exceptionOccurred` | `JobAttempted::$exception`   |
| `QueueBusy::$connection`           | `QueueBusy::$connectionName` |

***

## 컨트랙트 추가

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

커스텀 구현을 가지는 경우에만 영향이 있습니다.

### `Dispatcher` 컨트랙트

`Illuminate\Contracts\Bus\Dispatcher` 컨트랙트에 `dispatchAfterResponse($command, $handler = null)` 메서드가 추가되었습니다.

### `ResponseFactory` 컨트랙트

`Illuminate\Contracts\Routing\ResponseFactory` 컨트랙트에 `eventStream` 시그니처가 추가되었습니다.

### `MustVerifyEmail` 컨트랙트

`Illuminate\Contracts\Auth\MustVerifyEmail` 컨트랙트에 `markEmailAsUnverified()`가 추가되었습니다.

### `Queue` 컨트랙트

`Illuminate\Contracts\Queue\Queue` 컨트랙트에 이하의 큐 크기 검사 메서드가 추가되었습니다 (이전에는 docblock에서만 선언되어 있었습니다).

* `pendingSize`
* `delayedSize`
* `reservedSize`
* `creationTimeOfOldestPendingJob`

### `Store` / `Repository` 컨트랙트

캐시 컨트랙트에 TTL 연장을 위한 `touch` 메서드가 추가되었습니다.

```php theme={null}
// Illuminate\Contracts\Cache\Store
public function touch($key, $seconds);
```

***

## 새 기능의 하이라이트

### AI 어시스트 업그레이드 (Laravel Boost)

Laravel Boost는 공식 MCP 서버입니다. AI 에디터와 연동하여 `/upgrade-laravel-v13` 명령으로 업그레이드를 반자동화할 수 있습니다.

### `Sec-Fetch-Site` 헤더에 의한 요청 발신처 검증

`PreventRequestForgery` 미들웨어가 `Sec-Fetch-Site` 헤더를 이용한 추가 오리진 검증을 수행합니다. 이로 인해 CSRF 보호가 강화되어 있습니다.

### 캐시의 안전한 디시리얼라이제이션

`serializable_classes` 설정에 의해, 허가된 클래스만이 디시리얼라이즈되도록 되었습니다. PHP 디시리얼라이제이션 공격에 대한 보안이 향상되어 있습니다.

### SSE (Server-Sent Events)의 `eventStream`

`ResponseFactory` 컨트랙트에 `eventStream`이 추가되어, Server-Sent Events 지원이 개선되었습니다.

### 큐 가시성의 향상

`Queue` 컨트랙트의 `pendingSize`, `delayedSize`, `reservedSize` 등의 메서드에 의해, 큐의 상태를 보다 세밀하게 모니터링할 수 있게 되었습니다.

***

## 자주 있는 마이그레이션 시의 문제와 해결책

### 문제: CSRF 관련 테스트가 실패한다

**증상:** `VerifyCsrfToken`을 참조하고 있는 테스트가 클래스가 발견되지 않는 오류로 실패한다.

**해결책:** 모든 참조를 `PreventRequestForgery`로 갱신해 주세요.

```php theme={null}
// Before
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
->withoutMiddleware([VerifyCsrfToken::class]);

// After
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
->withoutMiddleware([PreventRequestForgery::class]);
```

### 문제: 캐시에서 오브젝트를 복원할 수 없다

**증상:** 캐시에서 취득한 데이터가 `null`이 되거나, `UnserializationFailedException`이 발생한다.

**해결책:** `config/cache.php`에서 `serializable_classes`에 사용할 클래스를 추가하거나, 캐시하는 값을 배열로 변환해 주세요.

```php theme={null}
'serializable_classes' => [
    App\Models\User::class,
    App\Data\SomeData::class,
],
```

### 문제: `JobAttempted` 리스너가 기능하지 않는다

**증상:** `$event->exceptionOccurred`가 `null`이나 미정의 오류가 된다.

**해결책:** `$event->exception !== null`로 변경해 주세요.

```php theme={null}
// Before
if ($event->exceptionOccurred) { ... }

// After
if ($event->exception !== null) { ... }
```

### 문제: 세션이 무효화된다

**증상:** 업그레이드 후에 사용자가 로그아웃된다.

**해결책:** 기본 세션 쿠키 이름이 변경되어 있습니다. `.env`에서 `SESSION_COOKIE`를 명시적으로 설정하여 이전 값을 유지해 주세요.

```ini theme={null}
SESSION_COOKIE=laravel_session
```

### 문제: 캐시 키가 발견되지 않는다

**증상:** 업그레이드 후에 캐시 미스가 증가한다.

**해결책:** 캐시 프리픽스가 변경되어 있습니다. `.env`에서 `CACHE_PREFIX`를 설정하거나, 캐시를 클리어해 주세요.

```shell theme={null}
php artisan cache:clear
```

***

## 참고 자료

* [공식 업그레이드 가이드 (영어)](https://laravel.com/docs/13.x/upgrade)
* [laravel/laravel 리포지토리의 차분 (12.x → 13.x)](https://github.com/laravel/laravel/compare/12.x...13.x)
* [Laravel Shift](https://laravelshift.com) — 업그레이드를 자동화하는 커뮤니티 서비스
* [Laravel Boost](https://github.com/laravel/boost) — AI 어시스트 업그레이드용 MCP 서버


## Related topics

- [Laravel 11에서 12로의 업그레이드 가이드](/ko/blog/upgrade-11-to-12.md)
- [Laravel 9에서 10으로의 업그레이드](/ko/blog/upgrade-9-to-10.md)
- [Laravel 8에서 9로의 업그레이드](/ko/blog/upgrade-8-to-9.md)
- [Laravel 10에서 11로의 업그레이드](/ko/blog/upgrade-10-to-11.md)
- [Laravel 13 신기능 정리](/ko/blog/laravel-13-new-features.md)
