10 min read
Technical Content Writer

Laravel 10 is no longer supported. Bug fixes ended on August 6, 2024, and security fixes ended on February 4, 2025. If your application still runs Laravel 10, it has not received a security patch in over a year, and upgrading should be on your roadmap.
That is the short answer most people searching for Laravel 10 need in 2026. The rest of this article covers the full picture: whether Laravel 10 is LTS, its exact support timeline and PHP requirements, what the release introduced when it shipped in 2023, and the practical path from Laravel 10 to a supported version. At Redberry, we maintain and upgrade Laravel applications for clients across the EU, UK, and US as one of only 8 Premier Laravel Partners worldwide, so the upgrade guidance below comes from work we do regularly, not theory.
No. Laravel 10 is not an LTS (long-term support) release, and neither is any other modern Laravel version. Laravel dropped the LTS designation after Laravel 6. Since then, every major release follows the same support policy: bug fixes for 18 months and security fixes for 2 years from the release date.
So when you see "Laravel 10 LTS" mentioned anywhere, treat it as outdated information. There is no extended support track to fall back on - once the 2-year security window closes, the version is end of life.
| Milestone | Date |
|---|---|
| Release | February 14, 2023 |
| Bug fixes ended | August 6, 2024 |
| Security fixes ended (end of life) | February 4, 2025 |
For context, here is where the neighboring versions stand as of 2026:
| Version | Released | Bug fixes until | Security fixes until |
|---|---|---|---|
| Laravel 10 | February 14, 2023 | August 6, 2024 | February 4, 2025 (EOL) |
| Laravel 11 | March 12, 2024 | September 3, 2025 | March 12, 2026 (EOL) |
| Laravel 12 | February 24, 2025 | August 13, 2026 | February 24, 2027 |
| Laravel 13 | March 17, 2026 | Q3 2027 | Q1 2028 |
Note that Laravel 11 has also reached end of life. If you are planning an upgrade from Laravel 10 in 2026, Laravel 11 is not a destination - it is at most a stepping stone on the way to Laravel 12 or 13.
Laravel 10 requires PHP 8.1 or newer. Support for PHP 8.0 and below was dropped entirely with this release. Laravel 10 is also compatible with PHP 8.2 and PHP 8.3.
This matters for upgrade planning in both directions. If you are stuck on PHP 8.0, you cannot move to Laravel 10 at all. And if you are upgrading beyond Laravel 10, the PHP floor keeps rising: Laravel 11 and 12 require PHP 8.2+, and Laravel 13 requires PHP 8.3+. In our upgrade projects, aligning the server's PHP version is usually the first task, before any framework code changes.
For anything in production, no. Running a framework version that no longer receives security patches means any newly discovered vulnerability in the framework stays unpatched in your application. For client-facing systems, and especially anything handling payments, personal data, or regulated workflows, that is a risk worth removing.
The good news is that Laravel's upgrade path is deliberately gentle. The core team has kept breaking changes minimal since Laravel 9, and the official upgrade guides estimate most version jumps at well under a day for a typical application. We cover the practical path in the upgrade section below.
Laravel 10 shipped on February 14, 2023, following the annual release schedule the team adopted with Laravel 9 (major versions previously shipped every six months). The release notes were smaller than in earlier versions - a pattern that has continued since, with each major release focusing on refinement rather than reinvention.
These were the changes that mattered most in day-to-day work. All of them remain part of the framework in Laravel 11, 12, and 13, so this section doubles as a record of where these now-standard features came from.
Laravel 10 updated the application skeleton and all framework stubs to use native argument and return types in every method signature, removing the old "doc block" type hints.
Laravel 9:
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
Laravel 10:
/**
* Get the path the user should be redirected to when they are not authenticated.
*/
protected function redirectTo(Request $request): ?string
{
return $request->expectsJson() ? null : route('login');
}
Parameter and return types on every method improved readability and error prevention, and set the convention the framework has followed ever since. Nuno Maduro handled the sweep across all files and repositories in one comprehensive PR. It is also the convention we apply in our own application code - typed signatures catch a class of bugs before they reach review.
The new process facade made invoking external processes - shell commands, CLI scripts - as ergonomic as the HTTP facade made API calls.
Basic usage:
use Illuminate\Support\Facades\Process;
$result = Process::run('ls -la');
$result->successful(); // determine if the process was successful
$result->failed(); // determine if the process failed
$result->exitCode(); // get the exit code of the process
$result->output(); // get the standard output of the process
$result->errorOutput(); // get the error output of the process
$result->throw(); // throw an exception if the process failed
$result->throwIf(condition); // throw an exception if the process failed and the given condition is true
For example, running pwd and printing the current directory:
$result = Process::run('pwd');
return $result->output();
Output: /pathtoproject/projectname/public
Running a command that does not exist:
$result = Process::run('ll');
return $result->errorOutput();
Output: sh: ll: command not found
The Process layer shipped with real depth from day one: output handling as it is received, asynchronous processes, process pools, rich testing via fake(), and stray-process prevention during tests. For long-running commands like npm run build, you can monitor the process, wait for completion, or stream output as it runs.
The fake() method is the piece we lean on most in test suites. A command that takes several seconds in reality:
\Illuminate\Support\Facades\Process::run('npm run build')->output();
executes instantly under a fake:
\Illuminate\Support\Facades\Process::fake();
$this->info(\Illuminate\Support\Facades\Process::run('npm run build')->output());
Laravel Pennant, maintained by core team member Tim MacDonald, arrived alongside Laravel 10 and gave the framework a first-party answer to feature flag management. It ships with an in-memory array driver and a database driver (the default).
Getting started takes three steps: install the package, publish the config file, run the migration. After migrating, a new features table appears in the database.
Feature flags let you ship functionality that is only visible to specific user groups - say, administrators or internal staff - without deploying separate code. You define features in a service provider such as AppServiceProvider:
public function boot(): void
{
Feature::define('new-dashboard-text', function () {
return true;
});
}
Returning true from the closure activates the feature for everyone. To scope it to certain users, for example employees and administrators:
Feature::define('new-dashboard-text', fn (User $user) => $user->isAdmin() || $user->isEmployee());
In Blade, the @feature directive gates the markup:
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
@feature('new-dashboard-text')
<!-- 'new-style' is active -->
<div class="p-6 text-gray-500">
{{ __("Welcome to the page!") }}
</div>
@else
<!-- 'new-style' is inactive -->
<div class="p-6 text-gray-900">
{{ __("You're logged in!") }}
</div>
@endfeature
</div>
Pennant resolves each user's flag once and stores the result in the features table. If a stored value later needs to change - say a user becomes an employee and should now see the feature - you either remove the stored record or activate the flag in code:
\Laravel\Pennant\Feature::activate('new-dashboard-text');
Checking a flag in application logic:
if (Feature::active('new-dashboard-text')) {
return to_route('dashboard');
}
Pennant remains the standard way to run controlled rollouts in Laravel today. We use it on client projects where a feature needs to reach internal users or a pilot group before general release.
The artisan test command gained a --profile option that surfaces the slowest tests in a suite.
test('sleep for 3 seconds', function () {
sleep(3);
});
Running php artisan test --profile ranks tests by execution time, which makes slow-suite cleanup a data-driven task instead of guesswork.
From Laravel 10, the built-in make commands no longer fail without arguments. Invoked bare, they prompt for what they need:
php artisan make:model
What should the model be named?
❯ Post
Would you like any of the following? [none]
none ..... 0
all ...... 1
factory .. 2
form requests .. 3
migration .. 4
policy ... 5
resource controller .. 6
seed ..... 7
❯ 2,3,4
INFO Model [app/Models/Post.php] created successfully.
INFO Factory [database/factories/PostFactory.php] created successfully.
INFO Migration [database/migrations/2023_03_27_151438_create_posts_table.php] created successfully.
The Str::password method generates a secure random password of a given length - by default 32 characters, mixing letters, numbers, and symbols, each of which can be toggled:
public static function password($length = 32, $letters = true, $numbers = true, $symbols = true, $spaces = false)
Examples:
> Str::password(10)
= "L>e~8Ns9;!"
> Str::password(letters: false)
= "{/\18{]69~_>:)%4//%61\9-%.-{~%|&"
> Str::password(numbers: false)
= "OomXSZUnWA,jWTgise%>hcEsQnB,D.\!"
The str() helper works too:
> str()->password()
= "ZmJn^dib)GO)qutEER%QXmgt)fqJ\PiC"
Useful for generating temporary user passwords, among other things.
Before Laravel 10, creating a project with Laravel Breeze and Pest meant three separate steps: install Laravel, install Breeze, install Pest. Laravel 10's installer collapsed that into flags - laravel new example-app --breeze --pest scaffolds everything in one command.
Worth noting in 2026: Breeze itself has since been retired. Laravel 12 replaced Breeze and Jetstream with new React, Vue, and Livewire starter kits, which we covered in our Laravel 12 release breakdown.
Methods marked deprecated in Laravel 9 were removed in Laravel 10. Migrating a project meant rewriting any code that used them:
$dates property on Eloquent models (use $casts instead)Route::home methodassertTimesSent methodScheduleListCommand's $defaultName propertydispatchNow functionalityIf you are on Laravel 10 in 2026, the sensible target is Laravel 12 or Laravel 13, not Laravel 11 (which is also end of life). The path we follow on client upgrade projects:
composer.json against each package's supported Laravel versions before starting.Each version step also unlocks meaningful capability: Laravel 11 brought the streamlined application structure, and Reverb for WebSockets (our Laravel 11 breakdown covers it), Laravel 12 brought the new starter kits, and Laravel 13 shipped with the first-party Laravel AI SDK - which we have written about in depth in our Laravel AI SDK practical guide, including how it relates to our own open-source agent package, LarAgent.
If the upgrade is bigger than your team wants to take on internally - a large codebase, thin test coverage, or several versions of drift - this is exactly the kind of work our Laravel development team handles. As a Premier Laravel Partner, we do version upgrades, audits, and long-term maintenance for applications across the EU, UK, and US. Feel free to get in touch - we're always happy to chat.
Keti leads editorial content at Redberry, writing and producing the company's technical articles, case studies and client interview series. Her work helps translate our team's first-hand engineering experience into helpful content for a global audience.
Last updated on Jul 20, 2026 by

We hosted the first official Laravel Meetup in Georgia, bringing together more than 100 attendees for an evening dedicated to Laravel, engineering, and community.
At our latest RDBR Meetup, we looked inside our two-year partnership with Tavistock Protect and the product we have been building together: PP Mobius.

We are a 200+ people agency and provide product design, software development, and creative growth marketing services to companies ranging from fresh startups to established enterprises. Our work has earned us 100+ international awards, partnerships with Laravel, Vue, Meta, and Google, and the title of Georgia’s agency of the year in 2019 and 2021.

