Article
Laravel12から13へ上げるときの注意点と確認項目
2026年3月17日にリリースされたLaravel13へ、Laravel12から上げる際に先に見ておきたいポイントを実務寄りに整理する。
Laravel13は、公式のRelease Notes上によると2026年3月17日にリリースされている。
Laravelのアップグレードは毎年時期が同じくらいで安定しているところはとても良いなと感じている。
今回のアップグレードは、公式ドキュメントでも「比較的軽いアップグレード」とされている。
ただし、実務では「変更点が少ないから楽」とは限らないこともあるので注意が必要の場合ももある。
例えば、アプリ本体のコード変更は問題なかったが、テスト、ミドルウェア指定、キャッシュ、イベントリスナーあたりで引っかかることもあるためだ。
なお、この記事では、公式Upgrade Guideの項目をそのまま並べるのではなく、Laravel12から13へ上げるときに先に見ておくと失敗しにくいようにまとめていきたいと思う。
まず最初に確認したいこと
最初に見るべきなのは次の4点である。
- PHPバージョンが8.3以上か
composer.jsonの依存更新が可能かVerifyCsrfTokenを直接参照していないか- キャッシュにPHPオブジェクトを雑に入れていないか
Laravel13自体は大きな破壊的変更が多い印象ではないが、周辺の条件が変わっている。
特にPHPの最低バージョンと、テスト・開発依存の更新可否は最初に見ておいた方がよい。
公式ドキュメントでも、依存更新の対象として laravel/framework, laravel/tinker, phpunit/phpunit, pestphp/pest などが挙がっている。
つまり、アプリ本体より先にComposer解決で止まる可能性があるということだ。
1. まずはPHP8.3を前提に動かせるか
Laravel13のRelease Notesでは、対応PHPバージョンが8.3 - 8.5とされている。
Laravel12は8.2 - 8.5だったので、8.2環境の場合、先にphpのバージョンを上げる必要がある。
実務では、コードより先に次のものを確認した方が速い。
- ローカル開発環境のPHP
- CIのPHP
- DockerイメージのPHP
- 本番サーバーのPHP
- Composer platform設定
Laravelのバージョンだけ上げても、CIや本番が8.2のままだと意味がない。
特にGitHub ActionsやDockerfileにバージョンが埋まっているケースは見落としやすいので注意が必要。
2. 依存関係はフレームワーク本体より先に詰まることがある
今回のupgrade guideでは、依存更新として次が案内されている。
laravel/frameworkを^13.0laravel/boostを^2.0laravel/tinkerを^3.0phpunit/phpunitを^12.0pestphp/pestを^4.0
この中で、実務的に先に確認したいのは phpunit と pest である。
フレームワーク本体は上がっても、テスト系や周辺パッケージの制約で止まることがある。
また、Laravel公式パッケージやコミュニティパッケージを多く使っている場合は、次も一緒に見ておいた方がよい。
- Horizon
- Sanctum
- Passport
- Telescope
- Livewire
- Inertia
- Laravel Pint
3. CSRFミドルウェア名の変更は影響が出やすい
今回、実務で一番該当が多い箇所はこの内容だと思う。
Laravel13では、CSRFミドルウェアが VerifyCsrfToken から PreventRequestForgery へ整理され、Sec-Fetch-Site を使ったorigin-awareな検証も入っている。
旧名の VerifyCsrfToken はdeprecated aliasとして残るが、直接クラス参照しているコードは見直した方がよい。
特に見ておきたいのは次の場所である。
- Featureテストの
withoutMiddleware(...) - ルート定義でのミドルウェア除外
- 独自ミドルウェア設定
- テストユーティリティ
つまり、「普通にアプリを使う分には動くが、テストだけ落ちる」系の変更である。
Laravel本体より、テストコードや一時的な回避コードに古いクラス名が残っていないかをgrepした方がよいだろう。
4. キャッシュにPHPオブジェクトを入れているなら見直したい
Laravel13では cache.serializable_classes が追加され、デフォルトでは false になっている。
これは、キャッシュ経由のPHPオブジェクトunserializeを強く制限する方向の変更である。
この変更はセキュリティ的にはかなり納得感があるが、既存コードでは次のような箇所が影響しやすい。
- DTOやValue Objectをそのままキャッシュしている
- Repository層でEloquentモデルやCollectionを丸ごとキャッシュしている
- ダッシュボード集計結果をオブジェクトで持っている
今までは雑にオブジェクトをキャッシュしていても動いていたコードが、Laravel13では方針転換を迫られる可能性がある。
個人的には、この機会に「配列やスカラーへ寄せられるものは寄せる」方が保守しやすいと思う。
例えば、次のようなコードは見直し対象である。
$summary = UserSummaryDto::fromModel($user);
Cache::put("user:summary:{$user->id}", $summary, 3600);
上記を、次のように配列へ落としてキャッシュしておく方が扱いやすい。
$summary = UserSummaryDto::fromModel($user);
Cache::put("user:summary:{$user->id}", [
'id' => $summary->id,
'name' => $summary->name,
'plan' => $summary->plan,
'last_login_at' => $summary->lastLoginAt?->toIso8601String(),
], 3600);
取得側でも、まず配列として受けて必要ならDTOへ戻す形にしておくと、キャッシュの中身が読みやすく、デバッグもしやすい。
同じように、Eloquent Collectionをそのまま入れるより、->map(fn ($row) => [...])->all() で必要項目だけ配列化しておく方が、serializeまわりの差分に引っかかりにくい。
5. キャッシュprefixとsession cookie名が暗黙依存だとずれる
これは高インパクトではないが、地味に面倒な変更である。
Laravel13では、デフォルト生成されるcache prefix / Redis prefix / session cookie名の規則が変わっている。
通常は config/cache.php や .env で明示設定していれば大きく困らない。
ただし、フレームワークのデフォルト生成値に暗黙依存していたアプリだと、アップグレード後に以下が変わる可能性がある。
- キャッシュキーのprefix
- Redis key prefix
- セッションCookie名
本番でこれが起こると、
- キャッシュが急に効かなくなる
- 既存セッションが切れたように見える
- Redis上で別prefix扱いになる
といった形で現れる。
アップグレード前に .env で CACHE_PREFIX, REDIS_PREFIX, SESSION_COOKIE を明示するのが安全である。
6. イベントやlistenerを細かく触っているなら地味な差分を見る
Laravel13は、大半のアプリでは影響が小さい一方で、イベントや低レイヤのフックを触っていると差分が出る。
特に見ておきたいのは次のあたりである。
JobAttemptedの$exceptionOccurredが$exceptionに変わるQueueBusyの$connectionが$connectionNameに変わる- manager
extendのcallback bindingが変わる
このあたりは、アプリ本体よりも監視、計測、独自driver拡張、保守用コードに潜みやすい。
大きな業務ロジックではなく、運用コードの方を先に疑った方が早い。
7. ルーティングとDBクエリの「今までたまたま動いていた」挙動に注意する
Laravel13のupgrade guideを見ると、明確なバグ修正寄りの変更も入っている。
例えば次の2つである。
- domain routeがnon-domain routeより優先される
- MySQLの
DELETE ... JOINにORDER BY/LIMITをちゃんと含める
前者は、サブドメイン付きルートやcatch-all的なルートを使っている場合に確認したい。
後者は、今までsilently ignoredされていたSQL条件がLaravel13では生成されるようになり、逆にDB側で QueryException になる可能性がある。
特に後者は、「Laravelが正しくなった結果、今までの雑な実装が落ちる」タイプなので、削除系バッチやメンテ用処理を軽く見直しておく価値がある。
8. Eloquentのboot周りのコードは確認する
Upgrade Guideでは、model boot中のnested instantiationが禁止され、LogicException になると書かれている。
つまり、boot() やtraitの bootXxx() の中で new static() するようなコードは危ない。
これは普通のCRUDではあまり踏まないが、共通traitやメタプログラミング寄りの設計をしていると引っかかることがある。
「昔書いた便利trait」があるなら、一度見ておいた方がよい。
例えば、slug生成用traitで次のようなコードを書いているケースは注意したい。
trait HasSlug
{
protected static function bootHasSlug(): void
{
static::creating(function ($model) {
$instance = new static();
$model->slug = $instance->buildSlug($model->title);
});
}
}
この例では creating の中で改めて new static() しており、Laravel13では問題化しやすい。
単にslugを作りたいだけなら、新しいインスタンスを作らず、イベントで渡される $model の値だけを使って処理する方が安全である。
例えば、次のように書いておけば boot中の入れ子のインスタンス生成を避けやすい。
trait HasSlug
{
protected static function bootHasSlug(): void
{
static::creating(function ($model) {
$model->slug = Str::slug($model->title);
});
}
}
もし共通処理として切り出したい場合でも、buildSlug(string $title): string のようにstaticメソッドや別サービスへ寄せて、model boot中に新しいmodelインスタンスを作らない形にしておく方が無難である。
実際のアップグレード手順としてはどう進めるか
自分なら次の順で進める。
- PHP 8.3 以上の環境を用意する
- Composer依存をLaravel13対応版へ更新する
- テストを全部流す
VerifyCsrfTokenの直接参照を置換する- キャッシュ・Redis・sessionのprefix明示設定を確認する
- キャッシュしているオブジェクトを洗う
- event / listener / custom driverを点検する
- ステージングでログとセッション挙動を確認する
今回のLaravel13は、公式にもある通り大規模な移行ではない。
ただ、軽いアップグレードほど「一見動くので見逃す」ことが起きやすい。
そのため、リクエスト処理・キャッシュ・テスト・運用コードに絞って先に見るのが効率的である。
まとめ
Laravel13は2026年3月17日リリースで、Laravel12から見ると比較的穏やかなメジャーアップグレードである。
ただし、実務上は次の点を先に見ると事故りにくい。
- PHP 8.3 以上が前提
- PHPUnit / Pestを含む依存更新
VerifyCsrfTokenの直接参照- cacheの
serializable_classes - cache / Redis / sessionのprefix変化
- queue eventやcustom driverまわり
- domain routeやjoined deleteの挙動差
「Laravel本体が大きく変わるか」よりも、「今まで暗黙で動いていたものがどこで変わるか」を見る方が、今回のアップグレードでは重要だと思う。
公式ドキュメント
前後の記事
関連記事
PHP8.4から8.5に上げるときの注意点と変更チェック項目
PHP8.4から8.5へ上げる際に、実務で確認しておきたい非互換やdeprecationの見どころを整理する。
Laravelでtruncateを使用する場合の注意点
Laravelでtruncateを使用する場合の注意点を実務の失敗例を踏まえて残しておく。
Laravelで作成したWebアプリをRust(Axum)に置き換えたときのログイン実装はどう考えるべきか
Laravelで作成したWebアプリをRust(Axum)に置き換えたときのログイン実装を、Laravel Sanctumとaxum-loginの違いを踏まえて整理する。
