What’s New in Laravel 11?

While Laravel 11 is still away, its release has already been announced to have taken place in Q1 2024. As with all major releases, this will surely bring new ideas and features to the framework, allowing us to abandon current deprecations at the same time. As it is always profitable to check what’s coming ahead of time to prepare ourselves for changes, today we will take a closer look at all the updates.
If you want to deep dive into the changes on your own, you can create the project with the newest version of Laravel using the following command:
composer create-project laravel/laravel:11.x-dev whats-new-laravel-11
Without any further ado, let’s see what we will find there.
PHP Version Upgraded To 8.2
The first noticeable change is that Laravel drops support for PHP 8.1 and, with the new version, requires a version equal to or above 8.2. As long as you have your application well-covered with an appropriate test suite, you may not have anything to worry about (you write tests, right? … right?). This may be a great opportunity to update PHP in your products to the newest version alongside Laravel.
Lightweight Application Scaffold
The next thing is that a lot of things were moved from the application scaffold deeper into the framework itself. Within the new project, you won’t find the Console, Exceptions, and Http/Middleware directories any longer. The Http/Kernel.php was also removed.
Don’t worry, though; the features configured with these files are not gone. They are now directly handled by the framework. The application itself is now configured with the app.php file provided in the bootstrap directory. You can add middlewares, handle exceptions, set up routing, as well as many other features in that file.
// bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
->withProviders()
->withRouting(
web: __DIR__.'/../routes/web.php',
// api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
// channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();As you can notice above, the API and broadcasting are not enabled by default. You won’t find routes/api.php nor routes/channels.php anymore. If you need these features, you can bring them back by simply calling:
php artisan install:api
php artisan install:broadcastingIn the Providers directory, you won’t find providers known from the previous version of Laravel because only AppServiceProvider is left. Others were removed. You can still register additional providers in bootstrap/providers.php whenever you need.
// bootstrap/providers.php
return [
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
//
];Streamlined Configuration
Going further with minimalism, Laravel drops all files present in the config directory. Now, the configuration of Laravel is completely handled by setting appropriate environment variables inside the .env file.
You can still publish all config files and have them in your source code if you wish, with the command:
php artisan config:publish
Or you may also decide to publish only one of them:
php artisan config:publish database
Following changes in environment variables were introduced:
APP_MAINTENANCE_DRIVER,APP_MAINTENANCE_STOREallows managing maintenance mode with file or cache mode. Going with cache, you may put multiple servers into maintenance at once.APP_PREVIOUS_KEYSallows handling the burden of the changedAPP_KEY. Whenever, for some reason, you have to regenerate this key yet some things were already encrypted with the old one, you may find the variable useful.CACHE_DRIVERvariable was replaced withCACHE_STORE.PUSHER_*andVITE_*variables were proposed to be removed from the scaffold, but as of this moment, the changes haven't been merged yet.
Model Casts Handling
Another significant change is the way of handling model casts. With the previous version, this was achieved with a protected property within the model. Laravel changes this to be handled via a dedicated method, which allows more flexible casting and arbitrary code execution.
You can still use the $casts property interchangeably with the casts method. Both casts will be merged together, but the casts method has higher priority.
class User
{
// ..
protected $casts = [
'email_verified_at' => 'datetime',
];
protected function casts(): array
{
return [
'password' => 'hashed',
];
}
}Database Tooling Refinements
New changes were also introduced in the area of database migrations management. Laravel won’t longer persist column definitions by default, which means that with the new version, we have to explicitly include all the modifiers when we want to alter the database column.
With the following example, default and comment definitions won’t be retained after the execution of the second migration.
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')
->unsigned()
->default(1)
->comment('my comment')
->change();
});
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')
->unsigned()
->change();
});This may affect old migrations in your source code, so deliberate consideration of the impact has to be applied before upgrading.
The spatial column types have been rewritten and unified under the geometry and geography methods, so you may consider using them instead of the previously available set of types. The isGeometry and projection column modifiers of the PostgreSQL grammar have been removed accordingly.
$table->geometry('dimension', subtype: 'polygon', srid: 0);
$table->geography('latitude', subtype: 'point', srid: 4326);Laravel is no longer dependent on Doctrine DBAL, and a bunch of classes and methods exposed from this package were removed or replaced with native Laravel implementation.
Replaced methods:
Schema::getAllTables()has been replaced withSchema::getTables()Schema::getAllViews()has been replaced withSchema::getViews()Schema::getAllTypes()has been replaced withSchema::getTypes()Schema::getColumnType()has been removed
Removed methods and properties:
Illuminate\Database\Schema\Builder::$alwaysUsesNativeSchemaOperationsIfPossibleIlluminate\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\PDOIlluminate\Database\DBAL\TimestampTypeIlluminate\Database\Schema\Grammars\ChangeColumnIlluminate\Database\Schema\Grammars\RenameColumnIlluminate\Database\Schema\Grammars\Grammar::getDoctrineTableDiff()
Another thing is that with the new version, Laravel applications use SQLite as the default database. Additionally, if your application is utilizing an SQLite database make sure that you have SQLite 3.35.0 or greater installed as this is minimal required version now.
Facades And Helpers Changes
Last but not least few usfull features have been introduced with the new version of Laravel. First of all we have once helper which may be used for callback value memoization. It expects callback as an argument and when once called it will always return the same value.
function foo(): string {
return Str::random(10);
}
function boo(): string {
return once(fn () => Str::random(10));
}
foo(); // "17BGhyCVLO"
foo(); // "DaV9UmydGW"
boo(); // "b6RkjEvkQX"
boo(); // "b6RkjEvkQX" - wow! it's no longer random :( The next helper is called literal, and it basically returns a new literal or anonymous object using named arguments.
literal(['a' => 1, 'b' => 2]); // array:2 ["a" => 1, "b" => 2]
literal(foo: 1, boo: 2); // stdClass {+"foo": 1, +"boo": 2}Furthermore, the cool new trait called Dumpable was added to Builder and Carbonclasses from Laravel. This trait exposes two methods, dump and dd, directly on the object where applied. Both of them allow dumping the content of the given object with additional arguments, but the second one additionally terminates the execution.
For example, the following code will dump the objects on which the method is executed.
\App\Models\User::find(1)->dump();
\Illuminate\Support\Carbon::now()->dump();Classes that implement the Enumerable interface expose new methods for intersections:
intersectUsing($items, $callback)intersects the collection with the given items using the callback.intersectAssoc($items)intersects the collection with the given items with additional index check.intersectAssocUsing($items, $callback)intersects the collection with the given items with additional index check, using the callback.
A new method for manipulating strings was exposed from the Str facade. Str::numbers($value) allows removing all non-numeric characters from the string.
Str::numbers('12ab34'); // 1234The signedRoute and temporarySignedRoute methods were added to the URL facade and correlated helpers to generate URLs with a signature.
URL::signedRoute('signed-route');
"http://localhost/signed-route?signature=eb63543a93faba67517843bbf57de7a6213e5854ba415e4ca184eca70b735799"
URL::temporarySignedRoute('signed-route', 6000);
"http://localhost/signed-route?expires=1707603869&signature=79683018e91b56cdfb083ec1ed2b3a98950d62403aa09738df8164406420dff7"Summary
As with each major version, Laravel brings a lot of changes. Thankfully, most of them don’t seem to have a large impact on existing applications. This article covered most of the changes without going too much into details, as before the official release, some things may still change. Even though many updates were covered here, there are still some left for you to discover.
I want to say thank you to all who read this article. I would love to hear your thoughts about all the changes in the new version of Laravel in the comments section, so feel free to share.
Don’t forget to check out my other articles for more tips and insights. Happy hacking!





