How would you move a municipal permit portal from Laravel 10 to Laravel 13, and why upgrade one major at a time?
answer
- Laravel 10 is past end of life
- PHP 8.3 is supported by 10 through 13
- one upgrade guide per hop
- tests green after every hop
- keep the old structure if it works
basics
~20 sMove PHP to 8.3 first, since Laravel 10 through 13 all support it, then upgrade 10 to 11, 11 to 12 and 12 to 13, following each upgrade guide and getting tests green after every hop.
solid answer
~50 sLaravel 10's security support ended on February 4th, 2025, so the portal is running unpatched and the goal is Laravel 13 (PHP 8.3 minimum, supported to March 2028). First move the servers to **PHP 8.3**: it is inside every range on the way (10: 8.1-8.3, 11: 8.2-8.4, 12: 8.2-8.5, 13: 8.3-8.5), so PHP and the framework never have to change in the same step. Then take **one major per hop**, because each upgrade guide describes only the changes from the previous major. On each hop: update `laravel/framework` and the first-party and third-party packages, work through that guide, fix deprecations, run the test suite, and ship or at least tag the result. The Laravel 11 slim skeleton is optional for an upgraded app; keep the Laravel 10 structure unless there is time to move it separately.
code
php · 10 lines<?php
use Illuminate\Support\Arr;
// Before (legacy laravel/helpers global): collides with the
// polyfilled array_first() that Laravel 13 brings in.
// $open = array_first($permits, fn ($p) => $p->status === 'open');
// After: the framework's own helper works on every version.
$open = Arr::first($permits, fn ($p) => $p->status === 'open');go deeper
Know that Laravel publishes one upgrade guide per major and that Laravel 13 needs PHP 8.3.
Explain why you follow the guides in order and why PHP 8.3 can be adopted before any framework change.
Lay out the hops, the package checks, the deprecation clean-up and the testing gate, and name the changes on each hop that bite an older app.
Weigh how long an end-of-life app may keep running, whether intermediate versions ship to production, and when to restructure versus only upgrade.
## Where the portal starts A permit portal on Laravel 10 is past **end of life**: bug fixes ended on August 6th, 2024 and security fixes on February 4th, 2025. The target, Laravel 13, requires **PHP 8.3** and gets security fixes until March 17th, 2028. ## Step 1: fix the PHP version first Each major supports a PHP range: | Laravel | PHP | |---|---| | 10 | 8.1 - 8.3 | | 11 | 8.2 - 8.4 | | 12 | 8.2 - 8.5 | | 13 | 8.3 - 8.5 | **PHP 8.3 is in every row.** Moving the servers and CI to 8.3 while the portal is still on Laravel 10 separates the PHP upgrade from the framework upgrades, so a failure always has one cause. After Laravel 13 is done, PHP 8.4 or 8.5 is a separate, later step. ## Step 2: one major per hop Laravel publishes one upgrade guide per major, and each describes the changes **from the previous major only**. Jumping from 10 straight to 13 means applying three guides at once and debugging their interactions. Hopping keeps each change set small: 1. **10 to 11**, then run the suite. 2. **11 to 12**, then run the suite. 3. **12 to 13**, then run the suite. On each hop: - Update `laravel/framework` and every first-party package (Sanctum, Horizon and so on) to the versions that support the new major; check third-party packages for support before starting. - Work through that major's upgrade guide, starting with the high-impact items. - Fix every deprecation the previous major announced, because the next major is where removals happen. - Get the tests green, then commit and ideally deploy. A shipped intermediate version is a safe point to return to. ## What to expect on each hop | Hop | Examples of changes to check | |---|---| | 10 to 11 | PHP 8.2 floor; the slim skeleton for new apps (optional for upgraded ones); column changes in migrations must restate every modifier to keep | | 11 to 12 | Carbon 3 required; `HasUuids` generates UUIDv7 (`HasVersion4Uuids` keeps the old ordered IDs); the `image` rule rejects SVG unless given `allow_svg` | | 12 to 13 | PHP 8.3 floor; the CSRF middleware's new class name; `symfony/polyfill-php85` defines global `array_first()`/`array_last()`, which collide with the legacy `laravel/helpers` package | The last row matters for an older portal: code that still calls the old global `array_first($array, $callback)` from `laravel/helpers` should move to `Arr::first()` before the hop to 13. ## Keep the Laravel 10 structure Laravel 11 introduced a slimmer skeleton for **new** applications: no `app/Http/Kernel.php`, middleware and exception handling configured in `bootstrap/app.php`, one service provider. An upgraded app does not have to adopt it. The framework still ships the HTTP and console kernel classes and the `RouteServiceProvider` base class, so the portal's existing kernel and providers keep working on 13. Restructuring is optional clean-up, best done as its own change after the version upgrades. ## Tools that help - The test suite is the real safety net; if coverage is thin, add feature tests for the core permit flows (apply, pay, approve) before starting. - Laravel Boost `^2.0` provides a `/upgrade-laravel-v13` command for AI assistants, for the final hop from a Laravel 12 app. - The upgrade guides also point to a community-maintained service that automates upgrades. ## Running the project - Freeze feature work on the portal, or keep it on a branch that is rebased after each hop, so the upgrade does not chase a moving target. - Keep a short log per hop: which guide items applied, which packages changed, which tests were fixed. It becomes the runbook for the next Laravel app the team upgrades. - Deploy each hop to a staging environment and exercise the permit flows by hand as well as through tests; configuration and queue behaviour often show problems that unit tests miss. ## Why not one big jump - Each guide assumes you start from the previous major. - Failures stay attributable to one hop. - Deprecations get fixed before the major that removes them. - If the project is interrupted, the portal is already on a newer, possibly still-supported major.
- Why upgrade PHP before the framework instead of during the Laravel 13 hop?PHP 8.3 is supported by Laravel 10, 11, 12 and 13, so it can be adopted first and left alone for the whole project. Changing PHP and the framework in the same step would make every failure ambiguous. Doing PHP first also exposes PHP-level deprecations early, on a framework version the team already knows.
- Must the portal adopt the Laravel 11 slim skeleton during the upgrade?No. The framework still contains the HTTP and console kernels and the RouteServiceProvider base class, so an app with the Laravel 10 structure keeps working on 13. Moving to bootstrap/app.php configuration is optional and safer as a separate change after the version upgrades are done.
- What should the team check before starting each hop?That every first-party and third-party package has a release supporting the target major, that deprecations from the current major are fixed, and that the test suite covers the core flows. A package without support for the next major blocks the hop, so find those first.
Upgrading one major at a time is like climbing a staircase rather than jumping to the landing: each step is small, you can stop on any of them, and a stumble costs one step instead of the whole flight.
saying these in an interview costs you the question
- Jump from 10 to 13 in one step to save time
- Upgrade PHP to 8.5 in the same commit as the framework
- The Laravel 11 slim skeleton must be adopted before reaching 13
- Laravel 13 removed the kernel classes, so old apps stop booting
- Only laravel/framework needs updating; packages follow automatically