업그레이드 가이드
번역일: 2026년 6월 25일
업그레이드 가이드
영향도 높은 변경사항
영향도 보통인 변경사항
영향도 낮은 변경사항
- Doctrine DBAL 제거
- Eloquent 모델
casts메서드 - 공간 타입(Spatial Types)
Enumerable컨트랙트UserProvider컨트랙트Authenticatable컨트랙트
10.x에서 11.0으로 업그레이드
예상 소요 시간: 약 15분
NOTE
이 문서는 모든 잠재적 브레이킹 체인지를 다루려 하지만, 일부 변경사항은 프레임워크의 특수한 영역에 해당하여 실제로 영향을 받는 경우가 적을 수 있습니다. 업그레이드 작업을 자동화하고 싶다면 Laravel Shift를 활용해 보세요.
의존성 업데이트
영향도: 높음
PHP 8.2.0 이상 필요
Laravel 11은 PHP 8.2.0 이상을 요구합니다.
curl 7.34.0 이상 필요
Laravel의 HTTP 클라이언트는 이제 curl 7.34.0 이상을 요구합니다.
Composer 의존성
composer.json 파일에서 아래 의존성을 업데이트하세요:
laravel/framework를^11.0으로nunomaduro/collision을^8.1로laravel/breeze를^2.0으로 (설치된 경우)laravel/cashier를^15.0으로 (설치된 경우)laravel/dusk를^8.0으로 (설치된 경우)laravel/jetstream을^5.0으로 (설치된 경우)laravel/octane을^2.3으로 (설치된 경우)laravel/passport를^12.0으로 (설치된 경우)laravel/sanctum을^4.0으로 (설치된 경우)laravel/scout를^10.0으로 (설치된 경우)laravel/spark-stripe를^5.0으로 (설치된 경우)laravel/telescope를^5.0으로 (설치된 경우)livewire/livewire를^3.4로 (설치된 경우)inertiajs/inertia-laravel을^1.0으로 (설치된 경우)
Cashier Stripe, Passport, Sanctum, Spark Stripe, Telescope 중 하나라도 사용하고 있다면, 이제 각 패키지가 자체 마이그레이션 디렉토리에서 마이그레이션을 자동으로 불러오지 않습니다. 따라서 아래 명령어로 마이그레이션 파일을 애플리케이션으로 퍼블리시해야 합니다:
php artisan vendor:publish --tag=cashier-migrationsphp artisan vendor:publish --tag=passport-migrationsphp artisan vendor:publish --tag=sanctum-migrationsphp artisan vendor:publish --tag=spark-migrationsphp artisan vendor:publish --tag=telescope-migrations각 패키지의 업그레이드 가이드도 반드시 확인하여 추가적인 브레이킹 체인지가 없는지 점검하세요:
Laravel 인스톨러를 전역으로 설치해 사용 중이라면 Composer로 업데이트하세요:
composer global require laravel/installer:^5.6마지막으로, 이전에 doctrine/dbal을 composer.json에 직접 추가했다면 제거해도 됩니다. Laravel 11은 이 패키지에 더 이상 의존하지 않습니다.
애플리케이션 구조
Laravel 11은 기본 파일 수를 줄인 새로운 애플리케이션 구조를 도입했습니다. 서비스 프로바이더, 미들웨어, 설정 파일이 기존보다 적습니다.
단, Laravel 10 애플리케이션을 11로 업그레이드할 때 애플리케이션 구조까지 새 구조로 마이그레이션하는 것은 권장하지 않습니다. Laravel 11은 Laravel 10의 구조도 그대로 지원하도록 설계되어 있습니다.
인증
비밀번호 재해싱
영향도: 낮음
Laravel 11은 인증 시, 해싱 알고리즘의 "작업 계수(work factor)"가 마지막 해싱 이후 변경된 경우 사용자 비밀번호를 자동으로 재해싱합니다.
일반적으로 이 변경이 애플리케이션에 문제를 일으키지는 않습니다. 다만 User 모델의 비밀번호 필드명이 password가 아닌 경우, 모델의 authPasswordName 프로퍼티로 필드명을 명시해야 합니다:
protected $authPasswordName = 'custom_password_field';
재해싱 기능을 완전히 비활성화하려면 config/hashing.php에 다음 옵션을 추가하세요:
'rehash_on_login' => false,
`UserProvider` 컨트랙트
영향도: 낮음
Illuminate\Contracts\Auth\UserProvider 컨트랙트에 rehashPasswordIfRequired 메서드가 추가되었습니다. 이 메서드는 애플리케이션의 해싱 알고리즘 작업 계수가 변경되었을 때 사용자 비밀번호를 재해싱하고 저장하는 역할을 합니다.
이 인터페이스를 직접 구현하는 클래스가 있다면 아래 메서드를 추가해야 합니다. 참고 구현은 Illuminate\Auth\EloquentUserProvider 클래스를 확인하세요:
public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false);`Authenticatable` 컨트랙트
영향도: 낮음
Illuminate\Contracts\Auth\Authenticatable 컨트랙트에 getAuthPasswordName 메서드가 추가되었습니다. 이 메서드는 인증 엔터티의 비밀번호 컬럼명을 반환합니다.
이 인터페이스를 직접 구현하는 클래스가 있다면 아래 메서드를 추가하세요:
public function getAuthPasswordName()
{
return 'password';
}Laravel 기본 User 모델은 Illuminate\Auth\Authenticatable 트레이트를 통해 이 메서드를 자동으로 제공받습니다.
`AuthenticationException` 클래스
영향도: 매우 낮음
Illuminate\Auth\AuthenticationException의 redirectTo 메서드가 이제 첫 번째 인수로 Illuminate\Http\Request 인스턴스를 요구합니다. 이 예외를 직접 처리하고 redirectTo 메서드를 호출하는 코드가 있다면 수정하세요:
if ($e instanceof AuthenticationException) {
$path = $e->redirectTo($request);
}회원가입 시 이메일 인증 알림
영향도: 매우 낮음
SendEmailVerificationNotification 리스너가 애플리케이션의 EventServiceProvider에 등록되어 있지 않으면 Registered 이벤트에 자동으로 등록됩니다. 만약 이 자동 등록을 원하지 않는다면 EventServiceProvider에 빈 configureEmailVerification 메서드를 정의하세요:
protected function configureEmailVerification()
{
// ...
}캐시
캐시 키 접두사
영향도: 매우 낮음
이전에는 DynamoDB, Memcached, Redis 캐시 스토어에서 캐시 키 접두사를 설정하면 Laravel이 접두사 뒤에 자동으로 :를 붙였습니다. Laravel 11부터는 :를 자동으로 추가하지 않습니다. 기존 방식을 유지하려면 접두사 설정값에 직접 :를 추가하세요.
컬렉션
`Enumerable` 컨트랙트
영향도: 낮음
Illuminate\Support\Enumerable 컨트랙트의 dump 메서드가 가변 인수(...$args)를 받도록 변경되었습니다. 이 인터페이스를 직접 구현하고 있다면 메서드 시그니처를 수정하세요:
public function dump(...$args);데이터베이스
SQLite 3.26.0 이상 필요
영향도: 높음
SQLite를 사용하는 경우 SQLite 3.26.0 이상이 필요합니다.
Eloquent 모델 `casts` 메서드
영향도: 낮음
기본 Eloquent 모델 클래스에 이제 casts 메서드가 정의됩니다. 애플리케이션의 모델에 casts라는 이름의 관계(relationship)가 정의되어 있다면 기본 클래스의 casts 메서드와 충돌할 수 있습니다.
컬럼 수정
영향도: 높음
컬럼을 수정할 때 변경 후에도 유지하고 싶은 모든 속성을 명시적으로 지정해야 합니다. 지정하지 않은 속성은 제거됩니다.
예를 들어, 아래처럼 unsigned, default, comment를 가진 votes 컬럼을 생성하는 마이그레이션이 있다고 가정합니다:
Schema::create('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('The vote count');
});이후 해당 컬럼을 nullable로 변경하는 마이그레이션을 작성할 때, Laravel 10에서는 기존 속성이 유지되었지만 Laravel 11에서는 명시적으로 선언하지 않은 속성은 제거됩니다:
// Laravel 11에서는 아래와 같이 기존 속성도 함께 명시해야 합니다.
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')
->unsigned()
->default(1)
->comment('The vote count')
->nullable()
->change();
});change 메서드는 인덱스에는 영향을 주지 않습니다. 컬럼 수정 시 인덱스를 추가하거나 제거하려면 인덱스 수정자를 명시적으로 사용하세요:
// 인덱스 추가
$table->bigIncrements('id')->primary()->change();
// 인덱스 제거
$table->char('postal_code', 10)->unique(false)->change();기존 마이그레이션을 모두 수정하기 어렵다면, 마이그레이션 스쿼시를 활용하세요:
php artisan schema:dump스쿼시 후에는 Laravel이 스키마 파일을 기준으로 데이터베이스를 마이그레이션한 뒤 미처리 마이그레이션을 실행합니다.
부동소수점 타입
영향도: 높음
double과 float 마이그레이션 컬럼 타입이 데이터베이스 전반에 걸쳐 일관성 있게 동작하도록 재작성되었습니다.
double 컬럼 타입은 이제 전체 자릿수와 소수점 자릿수 없이 표준 SQL 문법에 따른 DOUBLE 컬럼을 생성합니다. 기존에 전달하던 $total, $places 인수는 제거하세요:
$table->double('amount');float 컬럼 타입은 이제 $total, $places 인수 없이 FLOAT 컬럼을 생성하며, 선택적으로 $precision을 지정해 4바이트 단정밀도 또는 8바이트 배정밀도 컬럼을 선택할 수 있습니다:
$table->float('amount', precision: 53);unsignedDecimal, unsignedDouble, unsignedFloat 메서드는 제거되었습니다. MySQL에서 이 타입들의 unsigned 속성이 deprecated되었고 다른 데이터베이스에서도 표준화되지 않았기 때문입니다. 계속 사용해야 한다면 unsigned() 메서드를 체이닝하세요:
$table->decimal('amount', total: 8, places: 2)->unsigned();
$table->double('amount')->unsigned();
$table->float('amount', precision: 53)->unsigned();MariaDB 전용 드라이버
영향도: 매우 낮음
Laravel 11은 MariaDB 데이터베이스 전용 드라이버를 추가했습니다. 기존에는 MySQL 드라이버가 그대로 사용되었습니다.
MariaDB를 사용한다면 향후 MariaDB 전용 기능을 활용하기 위해 연결 설정의 드라이버를 변경할 수 있습니다:
'driver' => 'mariadb',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
// ...현재 새 MariaDB 드라이버는 MySQL 드라이버와 거의 동일하게 동작하지만, 한 가지 차이점이 있습니다: uuid 스키마 빌더 메서드가 char(36) 대신 네이티브 UUID 컬럼을 생성합니다.
기존 마이그레이션에서 uuid 메서드를 사용 중이고 mariadb 드라이버로 전환한다면, 예기치 않은 동작을 방지하기 위해 char로 변경하는 것을 고려하세요:
Schema::table('users', function (Blueprint $table) {
$table->char('uuid', 36);
// ...
});공간 타입(Spatial Types)
영향도: 낮음
데이터베이스 마이그레이션의 공간 컬럼 타입이 전체 데이터베이스에서 일관성 있게 동작하도록 재작성되었습니다. 기존의 point, lineString, polygon, geometryCollection, multiPoint, multiLineString, multiPolygon, multiPolygonZ 메서드 대신 geometry 또는 geography 메서드를 사용하세요:
$table->geometry('shapes');
$table->geography('coordinates');MySQL, MariaDB, PostgreSQL에서 저장 타입이나 공간 참조 시스템 식별자를 명시적으로 지정하려면 subtype과 srid를 전달하세요:
$table->geometry('dimension', subtype: 'polygon', srid: 0);
$table->geography('latitude', subtype: 'point', srid: 4326);PostgreSQL 문법의 isGeometry, projection 컬럼 수정자는 제거되었습니다.
Doctrine DBAL 제거
영향도: 낮음
아래에 나열된 Doctrine DBAL 관련 클래스와 메서드가 모두 제거되었습니다. Laravel은 더 이상 이 패키지에 의존하지 않으며, 커스텀 Doctrine 타입을 등록하지 않아도 다양한 컬럼 타입을 생성 및 변경할 수 있습니다:
Illuminate\Database\Schema\Builder::$alwaysUsesNativeSchemaOperationsIfPossible클래스 프로퍼티Illuminate\Database\Schema\Builder::useNativeSchemaOperationsIfPossible()메서드Illuminate\Database\Connection::usingNativeSchemaOperations()메서드Illuminate\Database\Connection::isDoctrineAvailable()메서드Illuminate\Database\Connection::getDoctrineConnection()메서드Illuminate\Database\Connection::getDoctrineSchemaManager()메서드Illuminate\Database\Connection::getDoctrineColumn()메서드Illuminate\Database\Connection::registerDoctrineType()메서드Illuminate\Database\DatabaseManager::registerDoctrineType()메서드Illuminate\Database\PDO디렉토리Illuminate\Database\DBAL\TimestampType클래스Illuminate\Database\Schema\Grammars\ChangeColumn클래스Illuminate\Database\Schema\Grammars\RenameColumn클래스Illuminate\Database\Schema\Grammars\Grammar::getDoctrineTableDiff()메서드
database 설정 파일의 dbal.types를 통해 커스텀 Doctrine 타입을 등록하는 것도 더 이상 필요하지 않습니다.
데이터베이스 테이블 정보를 조회할 때는 Laravel의 네이티브 스키마 메서드(Schema::getTables(), Schema::getColumns(), Schema::getIndexes(), Schema::getForeignKeys() 등)를 사용하세요.
Deprecated 스키마 메서드
영향도: 매우 낮음
Doctrine 기반의 Schema::getAllTables(), Schema::getAllViews(), Schema::getAllTypes() 메서드가 제거되었습니다. 대신 네이티브 메서드인 Schema::getTables(), Schema::getViews(), Schema::getTypes()를 사용하세요.
PostgreSQL과 SQL Server에서는 세 부분으로 구성된 참조(예: database.schema.table)가 지원되지 않습니다. 데이터베이스를 명시적으로 지정하려면 connection()을 사용하세요:
Schema::connection('database')->hasTable('schema.table');스키마 빌더 `getColumnType()` 메서드
영향도: 매우 낮음
Schema::getColumnType() 메서드는 이제 Doctrine DBAL 동등 타입이 아닌, 실제 컬럼 타입을 반환합니다.
데이터베이스 연결 인터페이스
영향도: 매우 낮음
Illuminate\Database\ConnectionInterface 인터페이스에 scalar 메서드가 추가되었습니다. 이 인터페이스를 직접 구현하는 클래스가 있다면 해당 메서드를 추가하세요:
public function scalar($query, $bindings = [], $useReadPdo = true);날짜
Carbon 3
영향도: 보통
Laravel 11은 Carbon 2와 Carbon 3을 모두 지원합니다. Carbon은 Laravel 생태계 전반에서 날짜 처리에 널리 사용되는 라이브러리입니다. Carbon 3으로 업그레이드할 경우 diffIn* 메서드가 부동소수점 숫자를 반환하며, 시간의 방향을 나타내기 위해 음수 값을 반환할 수 있습니다. 이는 Carbon 2와 크게 다른 점이므로 Carbon의 변경 로그와 마이그레이션 문서를 반드시 확인하세요.
메일
`Mailer` 컨트랙트
영향도: 매우 낮음
Illuminate\Contracts\Mail\Mailer 컨트랙트에 sendNow 메서드가 추가되었습니다. 이 컨트랙트를 직접 구현하는 클래스가 있다면 해당 메서드를 추가하세요:
public function sendNow($mailable, array $data = [], $callback = null);패키지
서비스 프로바이더 퍼블리싱
영향도: 매우 낮음
애플리케이션의 app/Providers 디렉토리에 서비스 프로바이더를 직접 퍼블리시하고, config/app.php의 providers 배열에 등록하는 방식의 Laravel 패키지를 작성한 경우, 새로운 ServiceProvider::addProviderToBootstrapFile 메서드를 사용하도록 패키지를 업데이트해야 합니다.
Laravel 11 신규 애플리케이션에서는 config/app.php에 providers 배열이 존재하지 않으므로, 이 메서드는 서비스 프로바이더를 bootstrap/providers.php 파일에 자동으로 추가합니다:
use Illuminate\Support\ServiceProvider;
ServiceProvider::addProviderToBootstrapFile(Provider::class);큐
`BatchRepository` 인터페이스
영향도: 매우 낮음
Illuminate\Bus\BatchRepository 인터페이스에 rollBack 메서드가 추가되었습니다. 이 인터페이스를 직접 구현하는 경우 해당 메서드를 추가하세요:
public function rollBack();데이터베이스 트랜잭션 내 동기 Job
영향도: 매우 낮음
이전에는 동기 Job(sync 큐 드라이버 사용)이 큐 연결의 after_commit 설정이나 Job의 afterCommit 메서드 호출 여부와 관계없이 즉시 실행되었습니다.
Laravel 11부터 동기 큐 Job도 큐 연결 또는 Job의 "after commit" 설정을 따릅니다.
요청 제한(Rate Limiting)
초 단위 요청 제한
영향도: 보통
Laravel 11은 분 단위에서 초 단위 요청 제한을 지원합니다. 이와 관련하여 아래의 브레이킹 체인지가 있습니다.
GlobalLimit 클래스의 생성자는 이제 분 대신 초를 받습니다. 이 클래스는 문서화되어 있지 않으므로 일반적으로 사용되지 않지만, 직접 사용했다면 수정하세요:
new GlobalLimit($attempts, 2 * 60);Limit 클래스의 생성자도 이제 분 대신 초를 받습니다. Limit::perMinute, Limit::perSecond 같은 정적 생성자를 통해 사용하는 경우에는 영향이 없지만, 생성자를 직접 호출했다면 초 단위로 변경하세요:
new Limit($key, $attempts, 2 * 60);Limit 클래스의 decayMinutes 프로퍼티가 decaySeconds로 이름이 바뀌었으며, 이제